imx.lists.linux.dev archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/8] Add ITE IT6263 LVDS to HDMI converter support
@ 2024-09-30  5:28 Liu Ying
  2024-09-30  5:28 ` [PATCH 1/8] arm64: dts: imx8mp-skov-revb-mi1010ait-1cp1: Add panel-timing node to panel node Liu Ying
                   ` (7 more replies)
  0 siblings, 8 replies; 38+ messages in thread
From: Liu Ying @ 2024-09-30  5:28 UTC (permalink / raw)
  To: dri-devel, devicetree, linux-kernel, imx, linux-arm-kernel
  Cc: andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart, jonas,
	jernej.skrabec, maarten.lankhorst, mripard, tzimmermann, airlied,
	simona, robh, krzk+dt, conor+dt, shawnguo, s.hauer, kernel,
	festevam, catalin.marinas, will, quic_bjorande, geert+renesas,
	dmitry.baryshkov, arnd, nfraprado, o.rempel, y.moog

Hi,

This patch series aims to add ITE IT6263 LVDS to HDMI converter on
i.MX8MP EVK.  Combined with LVDS receiver and HDMI 1.4a transmitter,
the IT6263 supports LVDS input and HDMI 1.4 output by conversion
function.  IT6263 product link can be found at [1].

Patch 1&2 are preparation patches to allow display modes of two
existing panels to pass the added mode validation logic in patch 4.

Patch 3 allows i.MX8MP LVDS Display Bridge(LDB) bridge driver to find
the next non-panel bridge, that is the IT6263 in this case.

Patch 4 adds mode validation logic to i.MX8MP LDB bridge driver against
"ldb" clock so that it can filter out unsupported display modes read
from EDID.

Patch 5 adds DT binding for IT6263.

Patch 6 adds IT6263 bridge driver.  Only video output is supported.

Patch 7 adds DT overlays to support NXP adapter cards[2][3] with IT6263
populated.

Patch 8 enables the IT6263 bridge driver in defconfig.

[1] https://www.ite.com.tw/en/product/cate1/IT6263
[2] https://www.nxp.com/part/IMX-LVDS-HDMI
[3] https://www.nxp.com/part/IMX-DLVDS-HDMI

Liu Ying (8):
  arm64: dts: imx8mp-skov-revb-mi1010ait-1cp1: Add panel-timing node to
    panel node
  arm64: dts: imx8mp-phyboard-pollux-rdk: Add panel-timing node to
    panel-lvds node
  drm/bridge: fsl-ldb: Get the next non-panel bridge
  drm/bridge: fsl-ldb: Use clk_round_rate() to validate "ldb" clock rate
  dt-bindings: display: bridge: Add ITE IT6263 LVDS to HDMI converter
  drm/bridge: Add ITE IT6263 LVDS to HDMI converter
  arm64: dts: imx8mp-evk: Add NXP LVDS to HDMI adapter cards
  arm64: defconfig: Enable ITE IT6263 driver

 .../bindings/display/bridge/ite,it6263.yaml   | 310 +++++++
 arch/arm64/boot/dts/freescale/Makefile        |   8 +
 .../imx8mp-evk-imx-lvds-hdmi-common.dtsi      |  29 +
 ...8mp-evk-lvds0-imx-dlvds-hdmi-channel0.dtso |  44 +
 ...imx8mp-evk-lvds0-imx-lvds-hdmi-common.dtsi |  42 +
 .../imx8mp-evk-lvds0-imx-lvds-hdmi.dtso       |  28 +
 ...8mp-evk-lvds1-imx-dlvds-hdmi-channel0.dtso |  44 +
 ...imx8mp-evk-lvds1-imx-lvds-hdmi-common.dtsi |  42 +
 .../imx8mp-evk-lvds1-imx-lvds-hdmi.dtso       |  28 +
 arch/arm64/boot/dts/freescale/imx8mp-evk.dts  |   6 +
 .../freescale/imx8mp-phyboard-pollux-rdk.dts  |  15 +
 .../imx8mp-skov-revb-mi1010ait-1cp1.dts       |  15 +
 arch/arm64/configs/defconfig                  |   1 +
 drivers/gpu/drm/bridge/Kconfig                |   8 +
 drivers/gpu/drm/bridge/Makefile               |   1 +
 drivers/gpu/drm/bridge/fsl-ldb.c              |  53 +-
 drivers/gpu/drm/bridge/ite-it6263.c           | 829 ++++++++++++++++++
 17 files changed, 1483 insertions(+), 20 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml
 create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-imx-lvds-hdmi-common.dtsi
 create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-lvds0-imx-dlvds-hdmi-channel0.dtso
 create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-lvds0-imx-lvds-hdmi-common.dtsi
 create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-lvds0-imx-lvds-hdmi.dtso
 create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-lvds1-imx-dlvds-hdmi-channel0.dtso
 create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-lvds1-imx-lvds-hdmi-common.dtsi
 create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-lvds1-imx-lvds-hdmi.dtso
 create mode 100644 drivers/gpu/drm/bridge/ite-it6263.c

-- 
2.34.1


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

* [PATCH 1/8] arm64: dts: imx8mp-skov-revb-mi1010ait-1cp1: Add panel-timing node to panel node
  2024-09-30  5:28 [PATCH 0/8] Add ITE IT6263 LVDS to HDMI converter support Liu Ying
@ 2024-09-30  5:28 ` Liu Ying
  2024-09-30  5:28 ` [PATCH 2/8] arm64: dts: imx8mp-phyboard-pollux-rdk: Add panel-timing node to panel-lvds node Liu Ying
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 38+ messages in thread
From: Liu Ying @ 2024-09-30  5:28 UTC (permalink / raw)
  To: dri-devel, devicetree, linux-kernel, imx, linux-arm-kernel
  Cc: andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart, jonas,
	jernej.skrabec, maarten.lankhorst, mripard, tzimmermann, airlied,
	simona, robh, krzk+dt, conor+dt, shawnguo, s.hauer, kernel,
	festevam, catalin.marinas, will, quic_bjorande, geert+renesas,
	dmitry.baryshkov, arnd, nfraprado, o.rempel, y.moog

Add a panel-timing node to panel node to override any fixed display
modes written in a panel driver.  This way, 68.9MHz clock frequency
specified in panel-timing node may accommodate 7-fold 482.3MHz
"media_ldb" clock which is derived from 964.6MHz "video_pll1" clock.
The above clock frequencies align to the clock rates assigned in the
lvds_bridge node and media_blk_ctrl node in this DT file.

This should be able to suppress this LDB driver warning:
[   17.206644] fsl-ldb 32ec0000.blk-ctrl:bridge@5c: Configured LDB clock (70000000 Hz) does not match requested LVDS clock: 490000000 Hz

This also makes the display mode used by the panel pass mode validation
against pixel clock rate and "media_ldb" clock rate in a certain display
driver.

Fixes: 6d382d51d979 ("arm64: dts: freescale: Add SKOV IMX8MP CPU revB board")
Signed-off-by: Liu Ying <victor.liu@nxp.com>
---
 .../freescale/imx8mp-skov-revb-mi1010ait-1cp1.dts | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-skov-revb-mi1010ait-1cp1.dts b/arch/arm64/boot/dts/freescale/imx8mp-skov-revb-mi1010ait-1cp1.dts
index 3c2efdc59bfa..4e9f76de7462 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-skov-revb-mi1010ait-1cp1.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-skov-revb-mi1010ait-1cp1.dts
@@ -13,6 +13,21 @@ panel {
 		backlight = <&backlight>;
 		power-supply = <&reg_tft_vcom>;
 
+		panel-timing {
+			clock-frequency = <68900000>;
+			hactive = <1280>;
+			vactive = <800>;
+			hfront-porch = <30>;
+			hback-porch = <30>;
+			hsync-len = <10>;
+			vfront-porch = <5>;
+			vback-porch = <5>;
+			vsync-len = <5>;
+			hsync-active = <0>;
+			vsync-active = <0>;
+			de-active = <1>;
+		};
+
 		port {
 			in_lvds0: endpoint {
 				remote-endpoint = <&ldb_lvds_ch0>;
-- 
2.34.1


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

* [PATCH 2/8] arm64: dts: imx8mp-phyboard-pollux-rdk: Add panel-timing node to panel-lvds node
  2024-09-30  5:28 [PATCH 0/8] Add ITE IT6263 LVDS to HDMI converter support Liu Ying
  2024-09-30  5:28 ` [PATCH 1/8] arm64: dts: imx8mp-skov-revb-mi1010ait-1cp1: Add panel-timing node to panel node Liu Ying
@ 2024-09-30  5:28 ` Liu Ying
  2024-09-30  5:28 ` [PATCH 3/8] drm/bridge: fsl-ldb: Get the next non-panel bridge Liu Ying
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 38+ messages in thread
From: Liu Ying @ 2024-09-30  5:28 UTC (permalink / raw)
  To: dri-devel, devicetree, linux-kernel, imx, linux-arm-kernel
  Cc: andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart, jonas,
	jernej.skrabec, maarten.lankhorst, mripard, tzimmermann, airlied,
	simona, robh, krzk+dt, conor+dt, shawnguo, s.hauer, kernel,
	festevam, catalin.marinas, will, quic_bjorande, geert+renesas,
	dmitry.baryshkov, arnd, nfraprado, o.rempel, y.moog

Add a panel-timing node to panel-lvds node to override any fixed
display modes written in a panel driver.  This way, 74.25MHz clock
frequency specified in panel-timing node may accommodate 7-fold
519.75MHz "media_ldb" clock which is derived from 1.0395GHz
"video_pll1" clock.

This should suppress this LDB driver warning:
[   17.923709] fsl-ldb 32ec0000.blk-ctrl:bridge@5c: Configured LDB clock (72400000 Hz) does not match requested LVDS clock: 506800000 Hz

This also makes the display mode used by the panel pass mode validation
against pixel clock rate and "media_ldb" clock rate in a certain display
driver.

Fixes: 326d86e197fc ("arm64: dts: imx8mp-phyboard-pollux-rdk: add etml panel support")
Signed-off-by: Liu Ying <victor.liu@nxp.com>
---
 .../dts/freescale/imx8mp-phyboard-pollux-rdk.dts  | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-rdk.dts b/arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-rdk.dts
index 50debe821c42..20cb5363cccb 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-rdk.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-rdk.dts
@@ -37,6 +37,21 @@ panel1_lvds: panel-lvds {
 		backlight = <&backlight_lvds>;
 		power-supply = <&reg_vcc_3v3_sw>;
 
+		panel-timing {
+			clock-frequency = <74250000>;
+			hactive = <1280>;
+			vactive = <800>;
+			hfront-porch = <72>;
+			hback-porch = <86>;
+			hsync-len = <2>;
+			vfront-porch = <15>;
+			vback-porch = <21>;
+			vsync-len = <2>;
+			hsync-active = <0>;
+			vsync-active = <0>;
+			de-active = <1>;
+		};
+
 		port {
 			panel1_in: endpoint {
 				remote-endpoint = <&ldb_lvds_ch1>;
-- 
2.34.1


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

* [PATCH 3/8] drm/bridge: fsl-ldb: Get the next non-panel bridge
  2024-09-30  5:28 [PATCH 0/8] Add ITE IT6263 LVDS to HDMI converter support Liu Ying
  2024-09-30  5:28 ` [PATCH 1/8] arm64: dts: imx8mp-skov-revb-mi1010ait-1cp1: Add panel-timing node to panel node Liu Ying
  2024-09-30  5:28 ` [PATCH 2/8] arm64: dts: imx8mp-phyboard-pollux-rdk: Add panel-timing node to panel-lvds node Liu Ying
@ 2024-09-30  5:28 ` Liu Ying
  2024-09-30  5:28 ` [PATCH 4/8] drm/bridge: fsl-ldb: Use clk_round_rate() to validate "ldb" clock rate Liu Ying
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 38+ messages in thread
From: Liu Ying @ 2024-09-30  5:28 UTC (permalink / raw)
  To: dri-devel, devicetree, linux-kernel, imx, linux-arm-kernel
  Cc: andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart, jonas,
	jernej.skrabec, maarten.lankhorst, mripard, tzimmermann, airlied,
	simona, robh, krzk+dt, conor+dt, shawnguo, s.hauer, kernel,
	festevam, catalin.marinas, will, quic_bjorande, geert+renesas,
	dmitry.baryshkov, arnd, nfraprado, o.rempel, y.moog

The next bridge in bridge chain could be a panel bridge or a non-panel
bridge.  Use devm_drm_of_get_bridge() to replace the combination
function calls of of_drm_find_panel() and devm_drm_panel_bridge_add()
to get either a panel bridge or a non-panel bridge, instead of getting
a panel bridge only.

Signed-off-by: Liu Ying <victor.liu@nxp.com>
---
 drivers/gpu/drm/bridge/fsl-ldb.c | 31 +++++++++++--------------------
 1 file changed, 11 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/bridge/fsl-ldb.c b/drivers/gpu/drm/bridge/fsl-ldb.c
index 0e4bac7dd04f..b559f3e0bef6 100644
--- a/drivers/gpu/drm/bridge/fsl-ldb.c
+++ b/drivers/gpu/drm/bridge/fsl-ldb.c
@@ -15,7 +15,6 @@
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_bridge.h>
 #include <drm/drm_of.h>
-#include <drm/drm_panel.h>
 
 #define LDB_CTRL_CH0_ENABLE			BIT(0)
 #define LDB_CTRL_CH0_DI_SELECT			BIT(1)
@@ -86,7 +85,7 @@ static const struct fsl_ldb_devdata fsl_ldb_devdata[] = {
 struct fsl_ldb {
 	struct device *dev;
 	struct drm_bridge bridge;
-	struct drm_bridge *panel_bridge;
+	struct drm_bridge *next_bridge;
 	struct clk *clk;
 	struct regmap *regmap;
 	const struct fsl_ldb_devdata *devdata;
@@ -117,7 +116,7 @@ static int fsl_ldb_attach(struct drm_bridge *bridge,
 {
 	struct fsl_ldb *fsl_ldb = to_fsl_ldb(bridge);
 
-	return drm_bridge_attach(bridge->encoder, fsl_ldb->panel_bridge,
+	return drm_bridge_attach(bridge->encoder, fsl_ldb->next_bridge,
 				 bridge, flags);
 }
 
@@ -292,9 +291,7 @@ static const struct drm_bridge_funcs funcs = {
 static int fsl_ldb_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
-	struct device_node *panel_node;
 	struct device_node *remote1, *remote2;
-	struct drm_panel *panel;
 	struct fsl_ldb *fsl_ldb;
 	int dual_link;
 
@@ -318,33 +315,27 @@ static int fsl_ldb_probe(struct platform_device *pdev)
 	if (IS_ERR(fsl_ldb->regmap))
 		return PTR_ERR(fsl_ldb->regmap);
 
-	/* Locate the remote ports and the panel node */
+	/* Locate the remote ports. */
 	remote1 = of_graph_get_remote_node(dev->of_node, 1, 0);
 	remote2 = of_graph_get_remote_node(dev->of_node, 2, 0);
 	fsl_ldb->ch0_enabled = (remote1 != NULL);
 	fsl_ldb->ch1_enabled = (remote2 != NULL);
-	panel_node = of_node_get(remote1 ? remote1 : remote2);
 	of_node_put(remote1);
 	of_node_put(remote2);
 
-	if (!fsl_ldb->ch0_enabled && !fsl_ldb->ch1_enabled) {
-		of_node_put(panel_node);
-		return dev_err_probe(dev, -ENXIO, "No panel node found");
-	}
+	if (!fsl_ldb->ch0_enabled && !fsl_ldb->ch1_enabled)
+		return dev_err_probe(dev, -ENXIO, "No next bridge node found");
 
 	dev_dbg(dev, "Using %s\n",
 		fsl_ldb_is_dual(fsl_ldb) ? "dual-link mode" :
 		fsl_ldb->ch0_enabled ? "channel 0" : "channel 1");
 
-	panel = of_drm_find_panel(panel_node);
-	of_node_put(panel_node);
-	if (IS_ERR(panel))
-		return PTR_ERR(panel);
-
-	fsl_ldb->panel_bridge = devm_drm_panel_bridge_add(dev, panel);
-	if (IS_ERR(fsl_ldb->panel_bridge))
-		return PTR_ERR(fsl_ldb->panel_bridge);
-
+	fsl_ldb->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node,
+						      fsl_ldb->ch0_enabled ? 1 : 2,
+						      0);
+	if (IS_ERR(fsl_ldb->next_bridge))
+		return dev_err_probe(dev, PTR_ERR(fsl_ldb->next_bridge),
+				     "failed to get next bridge\n");
 
 	if (fsl_ldb_is_dual(fsl_ldb)) {
 		struct device_node *port1, *port2;
-- 
2.34.1


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

* [PATCH 4/8] drm/bridge: fsl-ldb: Use clk_round_rate() to validate "ldb" clock rate
  2024-09-30  5:28 [PATCH 0/8] Add ITE IT6263 LVDS to HDMI converter support Liu Ying
                   ` (2 preceding siblings ...)
  2024-09-30  5:28 ` [PATCH 3/8] drm/bridge: fsl-ldb: Get the next non-panel bridge Liu Ying
@ 2024-09-30  5:28 ` Liu Ying
  2024-09-30  7:31   ` Maxime Ripard
  2024-09-30  5:29 ` [PATCH 5/8] dt-bindings: display: bridge: Add ITE IT6263 LVDS to HDMI converter Liu Ying
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 38+ messages in thread
From: Liu Ying @ 2024-09-30  5:28 UTC (permalink / raw)
  To: dri-devel, devicetree, linux-kernel, imx, linux-arm-kernel
  Cc: andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart, jonas,
	jernej.skrabec, maarten.lankhorst, mripard, tzimmermann, airlied,
	simona, robh, krzk+dt, conor+dt, shawnguo, s.hauer, kernel,
	festevam, catalin.marinas, will, quic_bjorande, geert+renesas,
	dmitry.baryshkov, arnd, nfraprado, o.rempel, y.moog

Multiple display modes could be read from a display device's EDID.
Use clk_round_rate() to validate the "ldb" clock rate for each mode
in drm_bridge_funcs::mode_valid() to filter unsupported modes out.

Also, if the "ldb" clock and the pixel clock are sibling in clock
tree, use clk_round_rate() to validate the pixel clock rate against
the "ldb" clock.  This is not done in display controller driver
because drm_crtc_helper_funcs::mode_valid() may not decide to do
the validation or not if multiple encoders are connected to the CRTC,
e.g., i.MX93 LCDIF may connect with MIPI DSI controller, LDB and
parallel display output simultaneously.

Signed-off-by: Liu Ying <victor.liu@nxp.com>
---
 drivers/gpu/drm/bridge/fsl-ldb.c | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/drivers/gpu/drm/bridge/fsl-ldb.c b/drivers/gpu/drm/bridge/fsl-ldb.c
index b559f3e0bef6..ee8471c86617 100644
--- a/drivers/gpu/drm/bridge/fsl-ldb.c
+++ b/drivers/gpu/drm/bridge/fsl-ldb.c
@@ -11,6 +11,7 @@
 #include <linux/of_graph.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
+#include <linux/units.h>
 
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_bridge.h>
@@ -64,6 +65,7 @@ struct fsl_ldb_devdata {
 	u32 lvds_ctrl;
 	bool lvds_en_bit;
 	bool single_ctrl_reg;
+	bool ldb_clk_pixel_clk_sibling;
 };
 
 static const struct fsl_ldb_devdata fsl_ldb_devdata[] = {
@@ -74,11 +76,13 @@ static const struct fsl_ldb_devdata fsl_ldb_devdata[] = {
 	[IMX8MP_LDB] = {
 		.ldb_ctrl = 0x5c,
 		.lvds_ctrl = 0x128,
+		.ldb_clk_pixel_clk_sibling = true,
 	},
 	[IMX93_LDB] = {
 		.ldb_ctrl = 0x20,
 		.lvds_ctrl = 0x24,
 		.lvds_en_bit = true,
+		.ldb_clk_pixel_clk_sibling = true,
 	},
 };
 
@@ -269,11 +273,29 @@ fsl_ldb_mode_valid(struct drm_bridge *bridge,
 		   const struct drm_display_info *info,
 		   const struct drm_display_mode *mode)
 {
+	unsigned long link_freq, pclk_rate, rounded_pclk_rate;
 	struct fsl_ldb *fsl_ldb = to_fsl_ldb(bridge);
 
 	if (mode->clock > (fsl_ldb_is_dual(fsl_ldb) ? 160000 : 80000))
 		return MODE_CLOCK_HIGH;
 
+	/* Validate "ldb" clock rate. */
+	link_freq = fsl_ldb_link_frequency(fsl_ldb, mode->clock);
+	if (link_freq != clk_round_rate(fsl_ldb->clk, link_freq))
+		return MODE_NOCLOCK;
+
+	/*
+	 * Use "ldb" clock to validate pixel clock rate,
+	 * if the two clocks are sibling.
+	 */
+	if (fsl_ldb->devdata->ldb_clk_pixel_clk_sibling) {
+		pclk_rate = mode->clock * HZ_PER_KHZ;
+
+		rounded_pclk_rate = clk_round_rate(fsl_ldb->clk, pclk_rate);
+		if (rounded_pclk_rate != pclk_rate)
+			return MODE_NOCLOCK;
+	}
+
 	return MODE_OK;
 }
 
-- 
2.34.1


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

* [PATCH 5/8] dt-bindings: display: bridge: Add ITE IT6263 LVDS to HDMI converter
  2024-09-30  5:28 [PATCH 0/8] Add ITE IT6263 LVDS to HDMI converter support Liu Ying
                   ` (3 preceding siblings ...)
  2024-09-30  5:28 ` [PATCH 4/8] drm/bridge: fsl-ldb: Use clk_round_rate() to validate "ldb" clock rate Liu Ying
@ 2024-09-30  5:29 ` Liu Ying
  2024-09-30  9:04   ` Biju Das
  2024-10-02  0:02   ` Rob Herring
  2024-09-30  5:29 ` [PATCH 6/8] drm/bridge: " Liu Ying
                   ` (2 subsequent siblings)
  7 siblings, 2 replies; 38+ messages in thread
From: Liu Ying @ 2024-09-30  5:29 UTC (permalink / raw)
  To: dri-devel, devicetree, linux-kernel, imx, linux-arm-kernel
  Cc: andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart, jonas,
	jernej.skrabec, maarten.lankhorst, mripard, tzimmermann, airlied,
	simona, robh, krzk+dt, conor+dt, shawnguo, s.hauer, kernel,
	festevam, catalin.marinas, will, quic_bjorande, geert+renesas,
	dmitry.baryshkov, arnd, nfraprado, o.rempel, y.moog

Document ITE IT6263 LVDS to HDMI converter.

Product link:
https://www.ite.com.tw/en/product/cate1/IT6263

Signed-off-by: Liu Ying <victor.liu@nxp.com>
---
 .../bindings/display/bridge/ite,it6263.yaml   | 310 ++++++++++++++++++
 1 file changed, 310 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml

diff --git a/Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml b/Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml
new file mode 100644
index 000000000000..97fb81e5bc4a
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml
@@ -0,0 +1,310 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/bridge/ite,it6263.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ITE IT6263 LVDS to HDMI converter
+
+maintainers:
+  - Liu Ying <victor.liu@nxp.com>
+
+description: |
+  The IT6263 is a high-performance single-chip De-SSC(De-Spread Spectrum) LVDS
+  to HDMI converter.  Combined with LVDS receiver and HDMI 1.4a transmitter,
+  the IT6263 supports LVDS input and HDMI 1.4 output by conversion function.
+  The built-in LVDS receiver can support single-link and dual-link LVDS inputs,
+  and the built-in HDMI transmitter is fully compliant with HDMI 1.4a/3D, HDCP
+  1.2 and backward compatible with DVI 1.0 specification.
+
+  The IT6263 also encodes and transmits up to 8 channels of I2S digital audio,
+  with sampling rate up to 192KHz and sample size up to 24 bits. In addition,
+  an S/PDIF input port takes in compressed audio of up to 192KHz frame rate.
+
+  The newly supported High-Bit Rate(HBR) audio by HDMI specifications v1.3 is
+  provided by the IT6263 in two interfaces: the four I2S input ports or the
+  S/PDIF input port.  With both interfaces the highest possible HBR frame rate
+  is supported at up to 768KHz.
+
+properties:
+  compatible:
+    const: ite,it6263
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+    description: audio master clock
+
+  clock-names:
+    const: mclk
+
+  reset-gpios:
+    maxItems: 1
+
+  ivdd-supply:
+    description: 1.8V digital logic power
+
+  ovdd-supply:
+    description: 3.3V I/O pin power
+
+  txavcc18-supply:
+    description: 1.8V HDMI analog frontend power
+
+  txavcc33-supply:
+    description: 3.3V HDMI analog frontend power
+
+  pvcc1-supply:
+    description: 1.8V HDMI frontend core PLL power
+
+  pvcc2-supply:
+    description: 1.8V HDMI frontend filter PLL power
+
+  avcc-supply:
+    description: 3.3V LVDS frontend power
+
+  anvdd-supply:
+    description: 1.8V LVDS frontend analog power
+
+  apvdd-supply:
+    description: 1.8V LVDS frontend PLL power
+
+  "#sound-dai-cells":
+    const: 0
+
+  ite,i2s-audio-fifo-sources:
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+    minItems: 1
+    maxItems: 4
+    items:
+      enum: [0, 1, 2, 3]
+    description:
+      Each array element indicates the pin number of an I2S serial data input
+      line which is connected to an audio FIFO, from audio FIFO0 to FIFO3.
+
+  ite,rl-channel-swap-audio-sources:
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+    minItems: 1
+    maxItems: 4
+    uniqueItems: true
+    items:
+      enum: [0, 1, 2, 3]
+    description:
+      Each array element indicates an audio source whose right channel and left
+      channel are swapped by this converter. For I2S, the element is the pin
+      number of an I2S serial data input line. For S/PDIF, the element is always
+      0.
+
+  ports:
+    $ref: /schemas/graph.yaml#/properties/ports
+
+    oneOf:
+      - properties:
+          port@0:
+            $ref: /schemas/graph.yaml#/properties/port
+            description: the first LVDS input link
+
+          port@1: false
+
+          port@2:
+            $ref: /schemas/graph.yaml#/properties/port
+            description: video port for the HDMI output
+
+          port@3:
+            $ref: /schemas/graph.yaml#/properties/port
+            description: sound input port
+
+        required:
+          - port@0
+          - port@2
+
+      - properties:
+          port@0:
+            $ref: /schemas/graph.yaml#/$defs/port-base
+            unevaluatedProperties: false
+            description: the first LVDS input link
+
+            properties:
+              dual-lvds-odd-pixels:
+                type: boolean
+                description: the first sink port for odd pixels
+
+              dual-lvds-even-pixels:
+                type: boolean
+                description: the first sink port for even pixels
+
+            oneOf:
+              - required: [dual-lvds-odd-pixels]
+              - required: [dual-lvds-even-pixels]
+
+          port@1:
+            $ref: /schemas/graph.yaml#/$defs/port-base
+            unevaluatedProperties: false
+            description: the second LVDS input link
+
+            properties:
+              dual-lvds-even-pixels:
+                type: boolean
+                description: the second sink port for even pixels
+
+              dual-lvds-odd-pixels:
+                type: boolean
+                description: the second sink port for odd pixels
+
+            oneOf:
+              - required: [dual-lvds-even-pixels]
+              - required: [dual-lvds-odd-pixels]
+
+          port@2:
+            $ref: /schemas/graph.yaml#/properties/port
+            description: video port for the HDMI output
+
+          port@3:
+            $ref: /schemas/graph.yaml#/properties/port
+            description: sound input port
+
+        required:
+          - port@0
+          - port@1
+          - port@2
+
+        allOf:
+          - if:
+              properties:
+                port@0:
+                  required:
+                    - dual-lvds-odd-pixels
+            then:
+              properties:
+                port@1:
+                  properties:
+                    dual-lvds-odd-pixels: false
+
+          - if:
+              properties:
+                port@0:
+                  required:
+                    - dual-lvds-even-pixels
+            then:
+              properties:
+                port@1:
+                  properties:
+                    dual-lvds-even-pixels: false
+
+required:
+  - compatible
+  - reg
+  - ivdd-supply
+  - ovdd-supply
+  - txavcc18-supply
+  - txavcc33-supply
+  - pvcc1-supply
+  - pvcc2-supply
+  - avcc-supply
+  - anvdd-supply
+  - apvdd-supply
+  - ports
+
+additionalProperties: false
+
+examples:
+  - |
+    /* single-link LVDS input */
+    #include <dt-bindings/gpio/gpio.h>
+
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        hdmi@4c {
+            compatible = "ite,it6263";
+            reg = <0x4c>;
+            reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
+            ivdd-supply = <&reg_buck5>;
+            ovdd-supply = <&reg_vext_3v3>;
+            txavcc18-supply = <&reg_buck5>;
+            txavcc33-supply = <&reg_vext_3v3>;
+            pvcc1-supply = <&reg_buck5>;
+            pvcc2-supply = <&reg_buck5>;
+            avcc-supply = <&reg_vext_3v3>;
+            anvdd-supply = <&reg_buck5>;
+            apvdd-supply = <&reg_buck5>;
+
+            ports {
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                port@0 {
+                    reg = <0>;
+
+                    it6263_lvds_link1: endpoint {
+                        remote-endpoint = <&ldb_lvds_ch0>;
+                    };
+                };
+
+                port@2 {
+                    reg = <2>;
+
+                    it6263_out: endpoint {
+                        remote-endpoint = <&hdmi_in>;
+                    };
+                };
+            };
+        };
+    };
+
+  - |
+    /* dual-link LVDS input */
+    #include <dt-bindings/gpio/gpio.h>
+
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        hdmi@4c {
+            compatible = "ite,it6263";
+            reg = <0x4c>;
+            reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
+            ivdd-supply = <&reg_buck5>;
+            ovdd-supply = <&reg_vext_3v3>;
+            txavcc18-supply = <&reg_buck5>;
+            txavcc33-supply = <&reg_vext_3v3>;
+            pvcc1-supply = <&reg_buck5>;
+            pvcc2-supply = <&reg_buck5>;
+            avcc-supply = <&reg_vext_3v3>;
+            anvdd-supply = <&reg_buck5>;
+            apvdd-supply = <&reg_buck5>;
+
+            ports {
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                port@0 {
+                    reg = <0>;
+                    dual-lvds-odd-pixels;
+
+                    it6263_lvds_link1_dual: endpoint {
+                        remote-endpoint = <&ldb_lvds_ch0>;
+                    };
+                };
+
+                port@1 {
+                    reg = <1>;
+                    dual-lvds-even-pixels;
+
+                    it6263_lvds_link2_dual: endpoint {
+                        remote-endpoint = <&ldb_lvds_ch1>;
+                    };
+                };
+
+                port@2 {
+                    reg = <2>;
+
+                    it6263_out_dual: endpoint {
+                        remote-endpoint = <&hdmi_in>;
+                    };
+                };
+            };
+        };
+    };
-- 
2.34.1


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

* [PATCH 6/8] drm/bridge: Add ITE IT6263 LVDS to HDMI converter
  2024-09-30  5:28 [PATCH 0/8] Add ITE IT6263 LVDS to HDMI converter support Liu Ying
                   ` (4 preceding siblings ...)
  2024-09-30  5:29 ` [PATCH 5/8] dt-bindings: display: bridge: Add ITE IT6263 LVDS to HDMI converter Liu Ying
@ 2024-09-30  5:29 ` Liu Ying
  2024-09-30  7:11   ` Maxime Ripard
                     ` (2 more replies)
  2024-09-30  5:29 ` [PATCH 7/8] arm64: dts: imx8mp-evk: Add NXP LVDS to HDMI adapter cards Liu Ying
  2024-09-30  5:29 ` [PATCH 8/8] arm64: defconfig: Enable ITE IT6263 driver Liu Ying
  7 siblings, 3 replies; 38+ messages in thread
From: Liu Ying @ 2024-09-30  5:29 UTC (permalink / raw)
  To: dri-devel, devicetree, linux-kernel, imx, linux-arm-kernel
  Cc: andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart, jonas,
	jernej.skrabec, maarten.lankhorst, mripard, tzimmermann, airlied,
	simona, robh, krzk+dt, conor+dt, shawnguo, s.hauer, kernel,
	festevam, catalin.marinas, will, quic_bjorande, geert+renesas,
	dmitry.baryshkov, arnd, nfraprado, o.rempel, y.moog

Add basic HDMI video output support. Currently, only RGB888 output
pixel format is supported.  At the LVDS input side, the driver
supports single LVDS link and dual LVDS links with "jeida-24" LVDS
mapping.

Product link:
https://www.ite.com.tw/en/product/cate1/IT6263

Signed-off-by: Liu Ying <victor.liu@nxp.com>
---
 drivers/gpu/drm/bridge/Kconfig      |   8 +
 drivers/gpu/drm/bridge/Makefile     |   1 +
 drivers/gpu/drm/bridge/ite-it6263.c | 829 ++++++++++++++++++++++++++++
 3 files changed, 838 insertions(+)
 create mode 100644 drivers/gpu/drm/bridge/ite-it6263.c

diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 3eb955333c80..93f99682a090 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -90,6 +90,14 @@ config DRM_FSL_LDB
 	help
 	  Support for i.MX8MP DPI-to-LVDS on-SoC encoder.
 
+config DRM_ITE_IT6263
+	tristate "ITE IT6263 LVDS/HDMI bridge"
+	depends on OF
+	select DRM_KMS_HELPER
+	select REGMAP_I2C
+	help
+	  ITE IT6263 LVDS to HDMI bridge chip driver.
+
 config DRM_ITE_IT6505
 	tristate "ITE IT6505 DisplayPort bridge"
 	depends on OF
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index 7df87b582dca..f3776dd473fd 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_DRM_CHRONTEL_CH7033) += chrontel-ch7033.o
 obj-$(CONFIG_DRM_CROS_EC_ANX7688) += cros-ec-anx7688.o
 obj-$(CONFIG_DRM_DISPLAY_CONNECTOR) += display-connector.o
 obj-$(CONFIG_DRM_FSL_LDB) += fsl-ldb.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
 obj-$(CONFIG_DRM_LONTIUM_LT9211) += lontium-lt9211.o
diff --git a/drivers/gpu/drm/bridge/ite-it6263.c b/drivers/gpu/drm/bridge/ite-it6263.c
new file mode 100644
index 000000000000..886588497bc1
--- /dev/null
+++ b/drivers/gpu/drm/bridge/ite-it6263.c
@@ -0,0 +1,829 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2024 NXP
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/media-bus-format.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_atomic_state_helper.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_connector.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_of.h>
+#include <drm/drm_probe_helper.h>
+
+/* -----------------------------------------------------------------------------
+ * LVDS registers
+ */
+
+/* LVDS software reset registers */
+#define LVDS_REG_05			0x05
+#define  REG_SOFT_P_RST			BIT(1)
+
+/* LVDS system configuration registers */
+/* 0x0b */
+#define LVDS_REG_0B			0x0b
+#define  REG_SSC_PCLK_RF		BIT(0)
+#define  REG_LVDS_IN_SWAP		BIT(1)
+
+/* LVDS test pattern gen control registers */
+/* 0x2c */
+#define LVDS_REG_2C			0x2c
+#define  REG_COL_DEP			GENMASK(1, 0)
+#define  BIT8				FIELD_PREP(REG_COL_DEP, 2)
+#define  OUT_MAP			BIT(4)
+#define  JEIDA				0
+#define  REG_DESSC_ENB			BIT(6)
+#define  DMODE				BIT(7)
+#define  DISO				BIT(7)
+#define  SISO				0
+
+#define LVDS_REG_3C			0x3c
+#define LVDS_REG_3F			0x3f
+#define LVDS_REG_47			0x47
+#define LVDS_REG_48			0x48
+#define LVDS_REG_4F			0x4f
+#define LVDS_REG_52			0x52
+
+/* -----------------------------------------------------------------------------
+ * HDMI registers are separated into three banks:
+ * 1) HDMI register common bank: 0x00 ~ 0x2f
+ */
+
+/* HDMI genernal registers */
+#define HDMI_REG_SW_RST			0x04
+#define  SOFTREF_RST			BIT(5)
+#define  SOFTA_RST			BIT(4)
+#define  SOFTV_RST			BIT(3)
+#define  AUD_RST			BIT(2)
+#define  HDCP_RST			BIT(0)
+#define  HDMI_RST_ALL			(SOFTREF_RST | SOFTA_RST | SOFTV_RST | \
+					 AUD_RST | HDCP_RST)
+
+#define HDMI_REG_SYS_STATUS		0x0e
+#define  HPDETECT			BIT(6)
+#define  TXVIDSTABLE			BIT(4)
+
+#define HDMI_REG_BANK_CTRL		0x0f
+#define  REG_BANK_SEL			BIT(0)
+
+/* HDMI System DDC control registers */
+#define HDMI_REG_DDC_MASTER_CTRL	0x10
+#define  MASTER_SEL_HOST		BIT(0)
+
+#define HDMI_REG_DDC_HEADER		0x11
+
+#define HDMI_REG_DDC_REQOFF		0x12
+#define HDMI_REG_DDC_REQCOUNT		0x13
+#define HDMI_REG_DDC_EDIDSEG		0x14
+
+#define HDMI_REG_DDC_CMD		0x15
+#define  DDC_CMD_EDID_READ		0x3
+#define  DDC_CMD_FIFO_CLR		0x9
+
+#define HDMI_REG_DDC_STATUS		0x16
+#define  DDC_DONE			BIT(7)
+#define  DDC_NOACK			BIT(5)
+#define  DDC_WAITBUS			BIT(4)
+#define  DDC_ARBILOSE			BIT(3)
+#define  DDC_ERROR			(DDC_NOACK | DDC_WAITBUS | DDC_ARBILOSE)
+
+#define HDMI_DDC_FIFO_BYTES		32
+#define HDMI_REG_DDC_READFIFO		0x17
+#define HDMI_REG_LVDS_PORT		0x1d /* LVDS input control I2C addr */
+#define HDMI_REG_LVDS_PORT_EN		0x1e
+#define LVDS_INPUT_CTRL_I2C_ADDR	0x33
+
+/* -----------------------------------------------------------------------------
+ * 2) HDMI register bank0: 0x30 ~ 0xff
+ */
+
+/* HDMI AFE registers */
+#define HDMI_REG_AFE_DRV_CTRL		0x61
+#define  AFE_DRV_PWD			BIT(5)
+#define  AFE_DRV_RST			BIT(4)
+
+#define HDMI_REG_AFE_XP_CTRL		0x62
+#define  AFE_XP_GAINBIT			BIT(7)
+#define  AFE_XP_ER0			BIT(4)
+#define  AFE_XP_RESETB			BIT(3)
+
+#define HDMI_REG_AFE_ISW_CTRL		0x63
+
+#define HDMI_REG_AFE_IP_CTRL		0x64
+#define  AFE_IP_GAINBIT			BIT(7)
+#define  AFE_IP_ER0			BIT(3)
+#define  AFE_IP_RESETB			BIT(2)
+
+/* HDMI input data format registers */
+#define HDMI_REG_INPUT_MODE		0x70
+#define  IN_RGB				0x00
+
+/* HDMI general control registers */
+#define HDMI_REG_HDMI_MODE		0xc0
+#define  TX_HDMI_MODE			BIT(0)
+
+#define HDMI_REG_GCP			0xc1
+#define  AVMUTE				BIT(0)
+#define  HDMI_COLOR_DEPTH		GENMASK(6, 4)
+#define  HDMI_COLOR_DEPTH_24		FIELD_PREP(HDMI_COLOR_DEPTH, 4)
+
+#define HDMI_REG_PKT_GENERAL_CTRL	0xc6
+#define  ENABLE_PKT			BIT(0)
+#define  REPEAT_PKT			BIT(1)
+
+/* -----------------------------------------------------------------------------
+ * 3) HDMI register bank1: 0x130 ~ 0x1ff (HDMI packet registers)
+ */
+
+/* AVI packet registers */
+#define HDMI_REG_AVI_DB1		0x158
+#define  AVI_DB1_COLOR_SPACE		GENMASK(6, 5)
+#define  AVI_COLOR_SPACE_RGB		FIELD_PREP(AVI_DB1_COLOR_SPACE, 0)
+
+#define MAX_PIXEL_CLOCK_KHZ		150000
+#define HIGH_PIXEL_CLOCK_KHZ		80000
+
+struct it6263 {
+	struct device *dev;
+	struct i2c_client *hdmi_i2c;
+	struct i2c_client *lvds_i2c;
+	struct regmap *hdmi_regmap;
+	struct regmap *lvds_regmap;
+	struct drm_bridge bridge;
+	struct drm_bridge *next_bridge;
+	struct drm_connector connector;
+	struct gpio_desc *reset_gpio;
+	bool lvds_dual_link;
+	bool lvds_link12_swap;
+};
+
+static inline struct it6263 *bridge_to_it6263(struct drm_bridge *bridge)
+{
+	return container_of(bridge, struct it6263, bridge);
+}
+
+static inline struct it6263 *connector_to_it6263(struct drm_connector *conn)
+{
+	return container_of(conn, struct it6263, connector);
+}
+
+static bool it6263_hdmi_writeable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case HDMI_REG_SW_RST:
+	case HDMI_REG_BANK_CTRL:
+	case HDMI_REG_DDC_MASTER_CTRL:
+	case HDMI_REG_DDC_HEADER:
+	case HDMI_REG_DDC_REQOFF:
+	case HDMI_REG_DDC_REQCOUNT:
+	case HDMI_REG_DDC_EDIDSEG:
+	case HDMI_REG_DDC_CMD:
+	case HDMI_REG_LVDS_PORT:
+	case HDMI_REG_LVDS_PORT_EN:
+	case HDMI_REG_AFE_DRV_CTRL:
+	case HDMI_REG_AFE_XP_CTRL:
+	case HDMI_REG_AFE_ISW_CTRL:
+	case HDMI_REG_AFE_IP_CTRL:
+	case HDMI_REG_INPUT_MODE:
+	case HDMI_REG_HDMI_MODE:
+	case HDMI_REG_GCP:
+	case HDMI_REG_PKT_GENERAL_CTRL:
+	case HDMI_REG_AVI_DB1:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool it6263_hdmi_readable_reg(struct device *dev, unsigned int reg)
+{
+	if (it6263_hdmi_writeable_reg(dev, reg))
+		return true;
+
+	switch (reg) {
+	case HDMI_REG_SYS_STATUS:
+	case HDMI_REG_DDC_STATUS:
+	case HDMI_REG_DDC_READFIFO:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool it6263_hdmi_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case HDMI_REG_SW_RST:
+	case HDMI_REG_SYS_STATUS:
+	case HDMI_REG_DDC_STATUS:
+	case HDMI_REG_DDC_READFIFO:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_range_cfg it6263_hdmi_range_cfg = {
+	.range_min = 0x00,
+	.range_max = HDMI_REG_AVI_DB1,
+	.selector_reg = HDMI_REG_BANK_CTRL,
+	.selector_mask = REG_BANK_SEL,
+	.selector_shift = 0,
+	.window_start = 0x00,
+	.window_len = 0x100,
+};
+
+static const struct regmap_config it6263_hdmi_regmap_config = {
+	.name = "it6263-hdmi",
+	.reg_bits = 8,
+	.val_bits = 8,
+	.writeable_reg = it6263_hdmi_writeable_reg,
+	.readable_reg = it6263_hdmi_readable_reg,
+	.volatile_reg = it6263_hdmi_volatile_reg,
+	.max_register = HDMI_REG_AVI_DB1,
+	.ranges = &it6263_hdmi_range_cfg,
+	.num_ranges = 1,
+	.cache_type = REGCACHE_MAPLE,
+};
+
+static bool it6263_lvds_writeable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case LVDS_REG_05:
+	case LVDS_REG_0B:
+	case LVDS_REG_2C:
+	case LVDS_REG_3C:
+	case LVDS_REG_3F:
+	case LVDS_REG_47:
+	case LVDS_REG_48:
+	case LVDS_REG_4F:
+	case LVDS_REG_52:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool it6263_lvds_readable_reg(struct device *dev, unsigned int reg)
+{
+	return it6263_lvds_writeable_reg(dev, reg);
+}
+
+static bool it6263_lvds_volatile_reg(struct device *dev, unsigned int reg)
+{
+	return reg == LVDS_REG_05;
+}
+
+static const struct regmap_config it6263_lvds_regmap_config = {
+	.name = "it6263-lvds",
+	.reg_bits = 8,
+	.val_bits = 8,
+	.writeable_reg = it6263_lvds_writeable_reg,
+	.readable_reg = it6263_lvds_readable_reg,
+	.volatile_reg = it6263_lvds_volatile_reg,
+	.max_register = LVDS_REG_52,
+	.cache_type = REGCACHE_MAPLE,
+};
+
+static const char * const it6263_supplies[] = {
+	"ivdd", "ovdd", "txavcc18", "txavcc33", "pvcc1", "pvcc2",
+	"avcc", "anvdd", "apvdd"
+};
+
+static int it6263_parse_dt(struct it6263 *it)
+{
+	struct device *dev = it->dev;
+	struct device_node *port0, *port1;
+	int ret = 0;
+
+	it->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 2, 0);
+	if (IS_ERR(it->next_bridge))
+		return dev_err_probe(dev, PTR_ERR(it->next_bridge),
+				     "failed to get next bridge\n");
+
+	port0 = of_graph_get_port_by_id(dev->of_node, 0);
+	port1 = of_graph_get_port_by_id(dev->of_node, 1);
+	if (port0 && port1) {
+		if (of_property_read_bool(port0, "dual-lvds-even-pixels") &&
+		    of_property_read_bool(port1, "dual-lvds-odd-pixels")) {
+			it->lvds_dual_link = true;
+			it->lvds_link12_swap = true;
+		} else if (of_property_read_bool(port0, "dual-lvds-odd-pixels") &&
+			   of_property_read_bool(port1, "dual-lvds-even-pixels")) {
+			it->lvds_dual_link = true;
+		}
+
+		if (!it->lvds_dual_link) {
+			dev_err(dev,
+				"failed to get LVDS dual link pixel order\n");
+			ret = -EINVAL;
+		}
+	} else if (port1) {
+		ret = -EINVAL;
+		dev_err(dev, "single input LVDS port1 is not supported\n");
+	} else if (!port0) {
+		ret = -EINVAL;
+		dev_err(dev, "no input LVDS port\n");
+	}
+
+	of_node_put(port0);
+	of_node_put(port1);
+
+	return ret;
+}
+
+static inline void it6263_reset(struct it6263 *it)
+{
+	if (!it->reset_gpio)
+		return;
+
+	gpiod_set_value_cansleep(it->reset_gpio, 0);
+	fsleep(1000);
+	gpiod_set_value_cansleep(it->reset_gpio, 1);
+	/* The chip maker says the low pulse should be at least 40ms. */
+	fsleep(40000);
+	gpiod_set_value_cansleep(it->reset_gpio, 0);
+	/* addtional time to wait the high voltage to be stable */
+	fsleep(5000);
+}
+
+static inline int it6263_lvds_set_i2c_addr(struct it6263 *it)
+{
+	int ret;
+
+	ret = regmap_write(it->hdmi_regmap, HDMI_REG_LVDS_PORT,
+			   LVDS_INPUT_CTRL_I2C_ADDR << 1);
+	if (ret)
+		return ret;
+
+	return regmap_write(it->hdmi_regmap, HDMI_REG_LVDS_PORT_EN, BIT(0));
+}
+
+static inline void it6263_lvds_reset(struct it6263 *it)
+{
+	/* AFE PLL reset */
+	regmap_write_bits(it->lvds_regmap, LVDS_REG_3C, BIT(0), 0x0);
+	fsleep(1000);
+	regmap_write_bits(it->lvds_regmap, LVDS_REG_3C, BIT(0), BIT(0));
+
+	/* software pixel clock domain reset */
+	regmap_write_bits(it->lvds_regmap, LVDS_REG_05, REG_SOFT_P_RST,
+			  REG_SOFT_P_RST);
+	fsleep(1000);
+	regmap_write_bits(it->lvds_regmap, LVDS_REG_05, REG_SOFT_P_RST, 0x0);
+	fsleep(10000);
+}
+
+static inline void it6263_lvds_set_interface(struct it6263 *it)
+{
+	/* color depth */
+	regmap_write_bits(it->lvds_regmap, LVDS_REG_2C, REG_COL_DEP, BIT8);
+	/* output mapping */
+	regmap_write_bits(it->lvds_regmap, LVDS_REG_2C, OUT_MAP, JEIDA);
+
+	if (it->lvds_dual_link) {
+		regmap_write_bits(it->lvds_regmap, LVDS_REG_2C, DMODE, DISO);
+		regmap_write_bits(it->lvds_regmap, LVDS_REG_52, BIT(1), BIT(1));
+	} else {
+		regmap_write_bits(it->lvds_regmap, LVDS_REG_2C, DMODE, SISO);
+		regmap_write_bits(it->lvds_regmap, LVDS_REG_52, BIT(1), 0);
+	}
+}
+
+static inline void it6263_lvds_set_afe(struct it6263 *it)
+{
+	regmap_write(it->lvds_regmap, LVDS_REG_3C, 0xaa);
+	regmap_write(it->lvds_regmap, LVDS_REG_3F, 0x02);
+	regmap_write(it->lvds_regmap, LVDS_REG_47, 0xaa);
+	regmap_write(it->lvds_regmap, LVDS_REG_48, 0x02);
+	regmap_write(it->lvds_regmap, LVDS_REG_4F, 0x11);
+
+	regmap_write_bits(it->lvds_regmap, LVDS_REG_0B, REG_SSC_PCLK_RF,
+			  REG_SSC_PCLK_RF);
+	regmap_write_bits(it->lvds_regmap, LVDS_REG_3C, 0x07, 0);
+	regmap_write_bits(it->lvds_regmap, LVDS_REG_2C, REG_DESSC_ENB,
+			  REG_DESSC_ENB);
+}
+
+static inline void it6263_lvds_sys_cfg(struct it6263 *it)
+{
+	regmap_write_bits(it->lvds_regmap, LVDS_REG_0B, REG_LVDS_IN_SWAP,
+			  it->lvds_link12_swap ? REG_LVDS_IN_SWAP : 0);
+}
+
+static inline void it6263_lvds_config(struct it6263 *it)
+{
+	it6263_lvds_reset(it);
+	it6263_lvds_set_interface(it);
+	it6263_lvds_set_afe(it);
+	it6263_lvds_sys_cfg(it);
+}
+
+static inline void it6263_hdmi_config(struct it6263 *it)
+{
+	regmap_write(it->hdmi_regmap, HDMI_REG_SW_RST, HDMI_RST_ALL);
+	regmap_write(it->hdmi_regmap, HDMI_REG_INPUT_MODE, IN_RGB);
+	regmap_write_bits(it->hdmi_regmap, HDMI_REG_GCP, HDMI_COLOR_DEPTH,
+			  HDMI_COLOR_DEPTH_24);
+	regmap_write_bits(it->hdmi_regmap, HDMI_REG_AVI_DB1,
+			  AVI_DB1_COLOR_SPACE, AVI_COLOR_SPACE_RGB);
+}
+
+static enum drm_connector_status it6263_detect(struct it6263 *it)
+{
+	unsigned int val;
+
+	regmap_read(it->hdmi_regmap, HDMI_REG_SYS_STATUS, &val);
+	if (val & HPDETECT)
+		return connector_status_connected;
+	else
+		return connector_status_disconnected;
+}
+
+static enum drm_connector_status
+it6263_connector_detect(struct drm_connector *connector, bool force)
+{
+	struct it6263 *it = connector_to_it6263(connector);
+
+	return it6263_detect(it);
+}
+
+static const struct drm_connector_funcs it6263_connector_funcs = {
+	.detect = it6263_connector_detect,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.destroy = drm_connector_cleanup,
+	.reset = drm_atomic_helper_connector_reset,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static int it6263_read_edid(void *data, u8 *buf, unsigned int block, size_t len)
+{
+	struct it6263 *it = data;
+	struct regmap *regmap = it->hdmi_regmap;
+	unsigned int start = (block % 2) * EDID_LENGTH;
+	unsigned int segment = block >> 1;
+	unsigned int count, val;
+	int ret;
+
+	regmap_write(regmap, HDMI_REG_DDC_MASTER_CTRL, MASTER_SEL_HOST);
+	regmap_write(regmap, HDMI_REG_DDC_HEADER, DDC_ADDR << 1);
+	regmap_write(regmap, HDMI_REG_DDC_EDIDSEG, segment);
+
+	while (len) {
+		/* clear DDC FIFO */
+		regmap_write(regmap, HDMI_REG_DDC_CMD, DDC_CMD_FIFO_CLR);
+
+		ret = regmap_read_poll_timeout(regmap, HDMI_REG_DDC_STATUS,
+					       val, val & DDC_DONE,
+					       2000, 10000);
+		if (ret) {
+			dev_err(it->dev, "failed to clear DDC FIFO:%d\n", ret);
+			return ret;
+		}
+
+		count = len > HDMI_DDC_FIFO_BYTES ? HDMI_DDC_FIFO_BYTES : len;
+
+		/* fire the read command */
+		regmap_write(regmap, HDMI_REG_DDC_REQOFF, start);
+		regmap_write(regmap, HDMI_REG_DDC_REQCOUNT, count);
+		regmap_write(regmap, HDMI_REG_DDC_CMD, DDC_CMD_EDID_READ);
+
+		start += count;
+		len -= count;
+
+		ret = regmap_read_poll_timeout(regmap, HDMI_REG_DDC_STATUS, val,
+					       val & (DDC_DONE | DDC_ERROR),
+					       20000, 250000);
+		if (ret && !(val & DDC_ERROR)) {
+			dev_err(it->dev, "failed to read EDID:%d\n", ret);
+			return ret;
+		}
+
+		if (val & DDC_ERROR) {
+			dev_err(it->dev, "DDC error\n");
+			return -EIO;
+		}
+
+		/* cache to buffer */
+		for (; count > 0; count--) {
+			regmap_read(regmap, HDMI_REG_DDC_READFIFO, &val);
+			*(buf++) = val;
+		}
+	}
+
+	return 0;
+}
+
+static int it6263_connector_get_modes(struct drm_connector *connector)
+{
+	struct it6263 *it = connector_to_it6263(connector);
+	const struct drm_edid *drm_edid;
+	int count;
+
+	drm_edid = drm_edid_read_custom(connector, it6263_read_edid, it);
+
+	drm_edid_connector_update(connector, drm_edid);
+	count = drm_edid_connector_add_modes(connector);
+
+	drm_edid_free(drm_edid);
+
+	return count;
+}
+
+static const struct drm_connector_helper_funcs it6263_connector_helper_funcs = {
+	.get_modes = it6263_connector_get_modes,
+};
+
+static int it6263_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 *mode = &crtc_state->adjusted_mode;
+
+	return mode->clock > MAX_PIXEL_CLOCK_KHZ ? -EINVAL : 0;
+}
+
+static void
+it6263_bridge_atomic_disable(struct drm_bridge *bridge,
+			     struct drm_bridge_state *old_bridge_state)
+{
+	struct it6263 *it = bridge_to_it6263(bridge);
+
+	regmap_write_bits(it->hdmi_regmap, HDMI_REG_GCP, AVMUTE, AVMUTE);
+	regmap_write(it->hdmi_regmap, HDMI_REG_PKT_GENERAL_CTRL, 0);
+	regmap_write(it->hdmi_regmap, HDMI_REG_AFE_DRV_CTRL,
+		     AFE_DRV_RST | AFE_DRV_PWD);
+}
+
+static void
+it6263_bridge_atomic_enable(struct drm_bridge *bridge,
+			    struct drm_bridge_state *old_bridge_state)
+{
+	struct drm_atomic_state *state = old_bridge_state->base.state;
+	struct it6263 *it = bridge_to_it6263(bridge);
+	const struct drm_crtc_state *crtc_state;
+	struct regmap *regmap = it->hdmi_regmap;
+	const struct drm_display_mode *mode;
+	struct drm_connector *connector;
+	bool is_stable = false;
+	struct drm_crtc *crtc;
+	unsigned int val;
+	bool pclk_high;
+	int i, ret;
+
+	connector = drm_atomic_get_new_connector_for_encoder(state,
+							     bridge->encoder);
+	crtc = drm_atomic_get_new_connector_state(state, connector)->crtc;
+	crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+	mode = &crtc_state->adjusted_mode;
+
+	regmap_write(regmap, HDMI_REG_HDMI_MODE, TX_HDMI_MODE);
+
+	/* HDMI AFE setup */
+	pclk_high = mode->clock > HIGH_PIXEL_CLOCK_KHZ ? true : false;
+	regmap_write(regmap, HDMI_REG_AFE_DRV_CTRL, AFE_DRV_RST);
+	if (pclk_high)
+		regmap_write(regmap, HDMI_REG_AFE_XP_CTRL,
+			     AFE_XP_GAINBIT | AFE_XP_RESETB);
+	else
+		regmap_write(regmap, HDMI_REG_AFE_XP_CTRL,
+			     AFE_XP_ER0 | AFE_XP_RESETB);
+	regmap_write(regmap, HDMI_REG_AFE_ISW_CTRL, 0x10);
+	if (pclk_high)
+		regmap_write(regmap, HDMI_REG_AFE_IP_CTRL,
+			     AFE_IP_GAINBIT | AFE_IP_RESETB);
+	else
+		regmap_write(regmap, HDMI_REG_AFE_IP_CTRL,
+			     AFE_IP_ER0 | AFE_IP_RESETB);
+
+	/* HDMI software video reset */
+	regmap_write_bits(regmap, HDMI_REG_SW_RST, SOFTV_RST, SOFTV_RST);
+	fsleep(1000);
+	regmap_write_bits(regmap, HDMI_REG_SW_RST, SOFTV_RST, 0);
+
+	/* reconfigure LVDS and retry several times in case video is instable */
+	for (i = 0; i < 3; i++) {
+		ret = regmap_read_poll_timeout(regmap, HDMI_REG_SYS_STATUS, val,
+					       val & TXVIDSTABLE,
+					       20000, 500000);
+		if (!ret) {
+			is_stable = true;
+			break;
+		}
+
+		it6263_lvds_config(it);
+	}
+
+	if (!is_stable)
+		dev_warn(it->dev, "failed to wait for video stable\n");
+
+	/* HDMI AFE reset release and power up */
+	regmap_write(regmap, HDMI_REG_AFE_DRV_CTRL, 0);
+
+	regmap_write_bits(regmap, HDMI_REG_GCP, AVMUTE, 0);
+
+	regmap_write(regmap, HDMI_REG_PKT_GENERAL_CTRL, ENABLE_PKT | REPEAT_PKT);
+}
+
+static enum drm_mode_status
+it6263_bridge_mode_valid(struct drm_bridge *bridge,
+			 const struct drm_display_info *info,
+			 const struct drm_display_mode *mode)
+{
+	return mode->clock > MAX_PIXEL_CLOCK_KHZ ? MODE_CLOCK_HIGH : MODE_OK;
+}
+
+static int it6263_bridge_attach(struct drm_bridge *bridge,
+				enum drm_bridge_attach_flags flags)
+{
+	struct it6263 *it = bridge_to_it6263(bridge);
+	int ret;
+
+	ret = drm_bridge_attach(bridge->encoder, it->next_bridge, bridge,
+				flags | DRM_BRIDGE_ATTACH_NO_CONNECTOR);
+	if (ret < 0)
+		return ret;
+
+	if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
+		return 0;
+
+	it->connector.polled = DRM_CONNECTOR_POLL_CONNECT |
+			       DRM_CONNECTOR_POLL_DISCONNECT;
+
+	ret = drm_connector_init(bridge->dev, &it->connector,
+				 &it6263_connector_funcs,
+				 DRM_MODE_CONNECTOR_HDMIA);
+	if (ret)
+		return ret;
+
+	drm_connector_helper_add(&it->connector,
+				 &it6263_connector_helper_funcs);
+	drm_connector_attach_encoder(&it->connector, bridge->encoder);
+
+	return 0;
+}
+
+static enum drm_connector_status it6263_bridge_detect(struct drm_bridge *bridge)
+{
+	struct it6263 *it = bridge_to_it6263(bridge);
+
+	return it6263_detect(it);
+}
+
+static const struct drm_edid *
+it6263_bridge_edid_read(struct drm_bridge *bridge,
+			struct drm_connector *connector)
+{
+	struct it6263 *it = bridge_to_it6263(bridge);
+
+	return drm_edid_read_custom(connector, it6263_read_edid, it);
+}
+
+static u32 *
+it6263_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
+					struct drm_bridge_state *bridge_state,
+					struct drm_crtc_state *crtc_state,
+					struct drm_connector_state *conn_state,
+					u32 output_fmt,
+					unsigned int *num_input_fmts)
+{
+	u32 *input_fmts;
+
+	input_fmts = kmalloc(sizeof(*input_fmts), GFP_KERNEL);
+	if (!input_fmts) {
+		*num_input_fmts = 0;
+		return NULL;
+	}
+
+	input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA;
+	*num_input_fmts = 1;
+
+	return input_fmts;
+}
+
+static const struct drm_bridge_funcs it6263_bridge_funcs = {
+	.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,
+	.attach = it6263_bridge_attach,
+	.mode_valid = it6263_bridge_mode_valid,
+	.atomic_disable = it6263_bridge_atomic_disable,
+	.atomic_enable = it6263_bridge_atomic_enable,
+	.atomic_check = it6263_bridge_atomic_check,
+	.detect = it6263_bridge_detect,
+	.edid_read = it6263_bridge_edid_read,
+	.atomic_get_input_bus_fmts = it6263_bridge_atomic_get_input_bus_fmts,
+};
+
+static int it6263_probe(struct i2c_client *client)
+{
+	struct device *dev = &client->dev;
+	struct it6263 *it;
+	int ret;
+
+	it = devm_kzalloc(dev, sizeof(*it), GFP_KERNEL);
+	if (!it)
+		return -ENOMEM;
+
+	it->dev = dev;
+	it->hdmi_i2c = client;
+
+	it->hdmi_regmap = devm_regmap_init_i2c(client,
+					       &it6263_hdmi_regmap_config);
+	if (IS_ERR(it->hdmi_regmap))
+		return dev_err_probe(dev, PTR_ERR(it->hdmi_regmap),
+				     "failed to init I2C regmap for HDMI\n");
+
+	it->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
+	if (IS_ERR(it->reset_gpio))
+		return dev_err_probe(dev, PTR_ERR(it->reset_gpio),
+				     "failed to get reset gpio\n");
+
+	ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(it6263_supplies),
+					     it6263_supplies);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to get power supplies\n");
+
+	ret = it6263_parse_dt(it);
+	if (ret)
+		return ret;
+
+	it6263_reset(it);
+
+	ret = it6263_lvds_set_i2c_addr(it);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to set I2C addr\n");
+
+	it->lvds_i2c = devm_i2c_new_dummy_device(dev, client->adapter,
+						 LVDS_INPUT_CTRL_I2C_ADDR);
+	if (IS_ERR(it->lvds_i2c))
+		dev_err_probe(it->dev, PTR_ERR(it->lvds_i2c),
+			      "failed to allocate I2C device for LVDS\n");
+
+	it->lvds_regmap = devm_regmap_init_i2c(it->lvds_i2c,
+					       &it6263_lvds_regmap_config);
+	if (IS_ERR(it->lvds_regmap))
+		return dev_err_probe(dev, PTR_ERR(it->lvds_regmap),
+				     "failed to init I2C regmap for LVDS\n");
+
+	it6263_lvds_config(it);
+	it6263_hdmi_config(it);
+
+	i2c_set_clientdata(client, it);
+
+	it->bridge.funcs = &it6263_bridge_funcs;
+	it->bridge.of_node = dev->of_node;
+	it->bridge.ops = DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_DETECT;
+	drm_bridge_add(&it->bridge);
+
+	return 0;
+}
+
+static void it6263_remove(struct i2c_client *client)
+{
+	struct it6263 *it = i2c_get_clientdata(client);
+
+	drm_bridge_remove(&it->bridge);
+}
+
+static const struct of_device_id it6263_of_match[] = {
+	{ .compatible = "ite,it6263", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, it6263_of_match);
+
+static const struct i2c_device_id it6263_i2c_ids[] = {
+	{ "it6263", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, it6263_i2c_ids);
+
+static struct i2c_driver it6263_driver = {
+	.probe = it6263_probe,
+	.remove = it6263_remove,
+	.driver = {
+		.name = "it6263",
+		.of_match_table = it6263_of_match,
+	},
+	.id_table = it6263_i2c_ids,
+};
+module_i2c_driver(it6263_driver);
+
+MODULE_DESCRIPTION("ITE Tech. Inc. IT6263 LVDS/HDMI bridge");
+MODULE_AUTHOR("Liu Ying <victor.liu@nxp.com>");
+MODULE_LICENSE("GPL");
-- 
2.34.1


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

* [PATCH 7/8] arm64: dts: imx8mp-evk: Add NXP LVDS to HDMI adapter cards
  2024-09-30  5:28 [PATCH 0/8] Add ITE IT6263 LVDS to HDMI converter support Liu Ying
                   ` (5 preceding siblings ...)
  2024-09-30  5:29 ` [PATCH 6/8] drm/bridge: " Liu Ying
@ 2024-09-30  5:29 ` Liu Ying
  2024-09-30  5:29 ` [PATCH 8/8] arm64: defconfig: Enable ITE IT6263 driver Liu Ying
  7 siblings, 0 replies; 38+ messages in thread
From: Liu Ying @ 2024-09-30  5:29 UTC (permalink / raw)
  To: dri-devel, devicetree, linux-kernel, imx, linux-arm-kernel
  Cc: andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart, jonas,
	jernej.skrabec, maarten.lankhorst, mripard, tzimmermann, airlied,
	simona, robh, krzk+dt, conor+dt, shawnguo, s.hauer, kernel,
	festevam, catalin.marinas, will, quic_bjorande, geert+renesas,
	dmitry.baryshkov, arnd, nfraprado, o.rempel, y.moog

One ITE IT6263 LVDS to HDMI converter is populated on NXP IMX-LVDS-HDMI
and IMX-DLVDS-HDMI adapter cards.

Card IMX-LVDS-HDMI supports single LVDS link(IT6263 link1).
Card IMX-DLVDS-HDMI supports dual LVDS links(IT6263 link1 and link2).

Only one card can be enabled with one i.MX8MP EVK.

Add dedicated overlays to support the below four connections:
1) imx8mp-evk-lvds0-imx-lvds-hdmi.dtso:
   i.MX8MP EVK LVDS0 connector <=> LVDS adapter card J6(IT6263 link1)

2) imx8mp-evk-lvds1-imx-lvds-hdmi.dtso:
   i.MX8MP EVK LVDS1 connector <=> LVDS adapter card J6(IT6263 link1)

3) imx8mp-evk-lvds0-imx-dlvds-hdmi-channel0.dtso:
   i.MX8MP EVK LVDS0 connector <=> DLVDS adapter card channel0(IT6263 link1)
   i.MX8MP EVK LVDS1 connector <=> DLVDS adapter card channel1(IT6263 link2)

4) imx8mp-evk-lvds1-imx-dlvds-hdmi-channel0.dtso:
   i.MX8MP EVK LVDS1 connector <=> DLVDS adapter card channel0(IT6263 link1)
   i.MX8MP EVK LVDS0 connector <=> DLVDS adapter card channel1(IT6263 link2)

Part links:
https://www.nxp.com/part/IMX-LVDS-HDMI
https://www.nxp.com/part/IMX-DLVDS-HDMI

Signed-off-by: Liu Ying <victor.liu@nxp.com>
---
 arch/arm64/boot/dts/freescale/Makefile        |  8 ++++
 .../imx8mp-evk-imx-lvds-hdmi-common.dtsi      | 29 ++++++++++++
 ...8mp-evk-lvds0-imx-dlvds-hdmi-channel0.dtso | 44 +++++++++++++++++++
 ...imx8mp-evk-lvds0-imx-lvds-hdmi-common.dtsi | 42 ++++++++++++++++++
 .../imx8mp-evk-lvds0-imx-lvds-hdmi.dtso       | 28 ++++++++++++
 ...8mp-evk-lvds1-imx-dlvds-hdmi-channel0.dtso | 44 +++++++++++++++++++
 ...imx8mp-evk-lvds1-imx-lvds-hdmi-common.dtsi | 42 ++++++++++++++++++
 .../imx8mp-evk-lvds1-imx-lvds-hdmi.dtso       | 28 ++++++++++++
 arch/arm64/boot/dts/freescale/imx8mp-evk.dts  |  6 +++
 9 files changed, 271 insertions(+)
 create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-imx-lvds-hdmi-common.dtsi
 create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-lvds0-imx-dlvds-hdmi-channel0.dtso
 create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-lvds0-imx-lvds-hdmi-common.dtsi
 create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-lvds0-imx-lvds-hdmi.dtso
 create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-lvds1-imx-dlvds-hdmi-channel0.dtso
 create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-lvds1-imx-lvds-hdmi-common.dtsi
 create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-lvds1-imx-lvds-hdmi.dtso

diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index 9d3df8b218a2..cc4333f49c2d 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -196,7 +196,15 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mp-verdin-wifi-dev.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-verdin-wifi-mallow.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-verdin-wifi-yavia.dtb
 
+imx8mp-evk-lvds0-imx-dlvds-hdmi-channel0-dtbs += imx8mp-evk.dtb imx8mp-evk-lvds0-imx-dlvds-hdmi-channel0.dtbo
+imx8mp-evk-lvds0-imx-lvds-hdmi-dtbs += imx8mp-evk.dtb imx8mp-evk-lvds0-imx-lvds-hdmi.dtbo
+imx8mp-evk-lvds1-imx-dlvds-hdmi-channel0-dtbs += imx8mp-evk.dtb imx8mp-evk-lvds1-imx-dlvds-hdmi-channel0.dtbo
+imx8mp-evk-lvds1-imx-lvds-hdmi-dtbs += imx8mp-evk.dtb imx8mp-evk-lvds1-imx-lvds-hdmi.dtbo
 imx8mp-evk-mx8-dlvds-lcd1-dtbs += imx8mp-evk.dtb imx8mp-evk-mx8-dlvds-lcd1.dtbo
+dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk-lvds0-imx-dlvds-hdmi-channel0.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk-lvds0-imx-lvds-hdmi.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk-lvds1-imx-dlvds-hdmi-channel0.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk-lvds1-imx-lvds-hdmi.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk-mx8-dlvds-lcd1.dtb
 
 imx8mp-tqma8mpql-mba8mpxl-lvds-dtbs += imx8mp-tqma8mpql-mba8mpxl.dtb imx8mp-tqma8mpql-mba8mpxl-lvds.dtbo
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk-imx-lvds-hdmi-common.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-evk-imx-lvds-hdmi-common.dtsi
new file mode 100644
index 000000000000..44b30e9b3fde
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mp-evk-imx-lvds-hdmi-common.dtsi
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2024 NXP
+ */
+
+/dts-v1/;
+/plugin/;
+
+&{/} {
+	lvds-hdmi-connector {
+		compatible = "hdmi-connector";
+		label = "J2";
+		type = "a";
+
+		port {
+			lvds2hdmi_connector_in: endpoint {
+				remote-endpoint = <&it6263_out>;
+			};
+		};
+	};
+};
+
+&lcdif2 {
+	status = "okay";
+};
+
+&lvds_bridge {
+	status = "okay";
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk-lvds0-imx-dlvds-hdmi-channel0.dtso b/arch/arm64/boot/dts/freescale/imx8mp-evk-lvds0-imx-dlvds-hdmi-channel0.dtso
new file mode 100644
index 000000000000..4008d2fd36d6
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mp-evk-lvds0-imx-dlvds-hdmi-channel0.dtso
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2024 NXP
+ */
+
+#include "imx8mp-evk-lvds0-imx-lvds-hdmi-common.dtsi"
+
+&it6263 {
+	ports {
+		port@0 {
+			reg = <0>;
+			dual-lvds-odd-pixels;
+
+			it6263_lvds_link1: endpoint {
+				remote-endpoint = <&ldb_lvds_ch0>;
+			};
+		};
+
+		port@1 {
+			reg = <1>;
+			dual-lvds-even-pixels;
+
+			it6263_lvds_link2: endpoint {
+				remote-endpoint = <&ldb_lvds_ch1>;
+			};
+		};
+	};
+};
+
+&lvds_bridge {
+	ports {
+		port@1 {
+			ldb_lvds_ch0: endpoint {
+				remote-endpoint = <&it6263_lvds_link1>;
+			};
+		};
+
+		port@2 {
+			ldb_lvds_ch1: endpoint {
+				remote-endpoint = <&it6263_lvds_link2>;
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk-lvds0-imx-lvds-hdmi-common.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-evk-lvds0-imx-lvds-hdmi-common.dtsi
new file mode 100644
index 000000000000..c276e084ac8a
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mp-evk-lvds0-imx-lvds-hdmi-common.dtsi
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2024 NXP
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include "imx8mp-evk-imx-lvds-hdmi-common.dtsi"
+
+&i2c2 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	it6263: hdmi@4c {
+		compatible = "ite,it6263";
+		reg = <0x4c>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_lvds_en>;
+		reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
+		ivdd-supply = <&reg_buck5>;
+		ovdd-supply = <&reg_vext_3v3>;
+		txavcc18-supply = <&reg_buck5>;
+		txavcc33-supply = <&reg_vext_3v3>;
+		pvcc1-supply = <&reg_buck5>;
+		pvcc2-supply = <&reg_buck5>;
+		avcc-supply = <&reg_vext_3v3>;
+		anvdd-supply = <&reg_buck5>;
+		apvdd-supply = <&reg_buck5>;
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@2 {
+				reg = <2>;
+
+				it6263_out: endpoint {
+					remote-endpoint = <&lvds2hdmi_connector_in>;
+				};
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk-lvds0-imx-lvds-hdmi.dtso b/arch/arm64/boot/dts/freescale/imx8mp-evk-lvds0-imx-lvds-hdmi.dtso
new file mode 100644
index 000000000000..9e11f261ad13
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mp-evk-lvds0-imx-lvds-hdmi.dtso
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2024 NXP
+ */
+
+#include "imx8mp-evk-lvds0-imx-lvds-hdmi-common.dtsi"
+
+&it6263 {
+	ports {
+		port@0 {
+			reg = <0>;
+
+			it6263_lvds_link1: endpoint {
+				remote-endpoint = <&ldb_lvds_ch0>;
+			};
+		};
+	};
+};
+
+&lvds_bridge {
+	ports {
+		port@1 {
+			ldb_lvds_ch0: endpoint {
+				remote-endpoint = <&it6263_lvds_link1>;
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk-lvds1-imx-dlvds-hdmi-channel0.dtso b/arch/arm64/boot/dts/freescale/imx8mp-evk-lvds1-imx-dlvds-hdmi-channel0.dtso
new file mode 100644
index 000000000000..af2e73e36a1b
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mp-evk-lvds1-imx-dlvds-hdmi-channel0.dtso
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2024 NXP
+ */
+
+#include "imx8mp-evk-lvds1-imx-lvds-hdmi-common.dtsi"
+
+&it6263 {
+	ports {
+		port@0 {
+			reg = <0>;
+			dual-lvds-even-pixels;
+
+			it6263_lvds_link1: endpoint {
+				remote-endpoint = <&ldb_lvds_ch1>;
+			};
+		};
+
+		port@1 {
+			reg = <1>;
+			dual-lvds-odd-pixels;
+
+			it6263_lvds_link2: endpoint {
+				remote-endpoint = <&ldb_lvds_ch0>;
+			};
+		};
+	};
+};
+
+&lvds_bridge {
+	ports {
+		port@1 {
+			ldb_lvds_ch0: endpoint {
+				remote-endpoint = <&it6263_lvds_link2>;
+			};
+		};
+
+		port@2 {
+			ldb_lvds_ch1: endpoint {
+				remote-endpoint = <&it6263_lvds_link1>;
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk-lvds1-imx-lvds-hdmi-common.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-evk-lvds1-imx-lvds-hdmi-common.dtsi
new file mode 100644
index 000000000000..7fb38f417e6e
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mp-evk-lvds1-imx-lvds-hdmi-common.dtsi
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2024 NXP
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include "imx8mp-evk-imx-lvds-hdmi-common.dtsi"
+
+&i2c3 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	it6263: hdmi@4c {
+		compatible = "ite,it6263";
+		reg = <0x4c>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_lvds_en>;
+		reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
+		ivdd-supply = <&reg_buck5>;
+		ovdd-supply = <&reg_vext_3v3>;
+		txavcc18-supply = <&reg_buck5>;
+		txavcc33-supply = <&reg_vext_3v3>;
+		pvcc1-supply = <&reg_buck5>;
+		pvcc2-supply = <&reg_buck5>;
+		avcc-supply = <&reg_vext_3v3>;
+		anvdd-supply = <&reg_buck5>;
+		apvdd-supply = <&reg_buck5>;
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@2 {
+				reg = <2>;
+
+				it6263_out: endpoint {
+					remote-endpoint = <&lvds2hdmi_connector_in>;
+				};
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk-lvds1-imx-lvds-hdmi.dtso b/arch/arm64/boot/dts/freescale/imx8mp-evk-lvds1-imx-lvds-hdmi.dtso
new file mode 100644
index 000000000000..527a893a71b2
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mp-evk-lvds1-imx-lvds-hdmi.dtso
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2024 NXP
+ */
+
+#include "imx8mp-evk-lvds1-imx-lvds-hdmi-common.dtsi"
+
+&it6263 {
+	ports {
+		port@0 {
+			reg = <0>;
+
+			it6263_lvds_link1: endpoint {
+				remote-endpoint = <&ldb_lvds_ch1>;
+			};
+		};
+	};
+};
+
+&lvds_bridge {
+	ports {
+		port@2 {
+			ldb_lvds_ch1: endpoint {
+				remote-endpoint = <&it6263_lvds_link1>;
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts
index d26930f1a9e9..68e12a752edd 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts
@@ -938,6 +938,12 @@ MX8MP_IOMUXC_SPDIF_TX__I2C5_SCL         0x400001c2
 		>;
 	};
 
+	pinctrl_lvds_en: lvdsengrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_GPIO1_IO10__GPIO1_IO10	0x1c0
+		>;
+	};
+
 	pinctrl_pcie0: pcie0grp {
 		fsl,pins = <
 			MX8MP_IOMUXC_I2C4_SCL__PCIE_CLKREQ_B	0x60 /* open drain, pull up */
-- 
2.34.1


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

* [PATCH 8/8] arm64: defconfig: Enable ITE IT6263 driver
  2024-09-30  5:28 [PATCH 0/8] Add ITE IT6263 LVDS to HDMI converter support Liu Ying
                   ` (6 preceding siblings ...)
  2024-09-30  5:29 ` [PATCH 7/8] arm64: dts: imx8mp-evk: Add NXP LVDS to HDMI adapter cards Liu Ying
@ 2024-09-30  5:29 ` Liu Ying
  7 siblings, 0 replies; 38+ messages in thread
From: Liu Ying @ 2024-09-30  5:29 UTC (permalink / raw)
  To: dri-devel, devicetree, linux-kernel, imx, linux-arm-kernel
  Cc: andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart, jonas,
	jernej.skrabec, maarten.lankhorst, mripard, tzimmermann, airlied,
	simona, robh, krzk+dt, conor+dt, shawnguo, s.hauer, kernel,
	festevam, catalin.marinas, will, quic_bjorande, geert+renesas,
	dmitry.baryshkov, arnd, nfraprado, o.rempel, y.moog

ITE IT6263 LVDS to HDMI converter is populated on NXP IMX-LVDS-HDMI
and IMX-DLVDS-HDMI adapter cards.  The adapter cards can connect to
i.MX8MP EVK base board to support video output through HDMI connectors.
Build the ITE IT6263 driver as a module.

Signed-off-by: Liu Ying <victor.liu@nxp.com>
---
 arch/arm64/configs/defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 5fdbfea7a5b2..d8a232e285d4 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -899,6 +899,7 @@ CONFIG_DRM_PANEL_SITRONIX_ST7703=m
 CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA=m
 CONFIG_DRM_PANEL_VISIONOX_VTDR6130=m
 CONFIG_DRM_FSL_LDB=m
+CONFIG_DRM_ITE_IT6263=m
 CONFIG_DRM_LONTIUM_LT8912B=m
 CONFIG_DRM_LONTIUM_LT9611=m
 CONFIG_DRM_LONTIUM_LT9611UXC=m
-- 
2.34.1


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

* Re: [PATCH 6/8] drm/bridge: Add ITE IT6263 LVDS to HDMI converter
  2024-09-30  5:29 ` [PATCH 6/8] drm/bridge: " Liu Ying
@ 2024-09-30  7:11   ` Maxime Ripard
  2024-09-30  8:44     ` Liu Ying
  2024-09-30  9:16   ` Biju Das
  2024-10-02 10:19   ` Biju Das
  2 siblings, 1 reply; 38+ messages in thread
From: Maxime Ripard @ 2024-09-30  7:11 UTC (permalink / raw)
  To: Liu Ying
  Cc: dri-devel, devicetree, linux-kernel, imx, linux-arm-kernel,
	andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart, jonas,
	jernej.skrabec, maarten.lankhorst, tzimmermann, airlied, simona,
	robh, krzk+dt, conor+dt, shawnguo, s.hauer, kernel, festevam,
	catalin.marinas, will, quic_bjorande, geert+renesas,
	dmitry.baryshkov, arnd, nfraprado, o.rempel, y.moog

[-- Attachment #1: Type: text/plain, Size: 619 bytes --]

Hi,

On Mon, Sep 30, 2024 at 01:29:01PM GMT, Liu Ying wrote:
> Add basic HDMI video output support. Currently, only RGB888 output
> pixel format is supported.  At the LVDS input side, the driver
> supports single LVDS link and dual LVDS links with "jeida-24" LVDS
> mapping.
> 
> Product link:
> https://www.ite.com.tw/en/product/cate1/IT6263
> 
> Signed-off-by: Liu Ying <victor.liu@nxp.com>

Generally speaking, you need to use the new HDMI bridge infrastructure.
There's a lot of required things you're not dealing with here (such as
infoframes)

Also, you should add a MAINTAINERS entry

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 273 bytes --]

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

* Re: [PATCH 4/8] drm/bridge: fsl-ldb: Use clk_round_rate() to validate "ldb" clock rate
  2024-09-30  5:28 ` [PATCH 4/8] drm/bridge: fsl-ldb: Use clk_round_rate() to validate "ldb" clock rate Liu Ying
@ 2024-09-30  7:31   ` Maxime Ripard
  2024-09-30  7:55     ` Liu Ying
  0 siblings, 1 reply; 38+ messages in thread
From: Maxime Ripard @ 2024-09-30  7:31 UTC (permalink / raw)
  To: Liu Ying
  Cc: dri-devel, devicetree, linux-kernel, imx, linux-arm-kernel,
	andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart, jonas,
	jernej.skrabec, maarten.lankhorst, tzimmermann, airlied, simona,
	robh, krzk+dt, conor+dt, shawnguo, s.hauer, kernel, festevam,
	catalin.marinas, will, quic_bjorande, geert+renesas,
	dmitry.baryshkov, arnd, nfraprado, o.rempel, y.moog

[-- Attachment #1: Type: text/plain, Size: 3043 bytes --]

On Mon, Sep 30, 2024 at 01:28:59PM GMT, Liu Ying wrote:
> Multiple display modes could be read from a display device's EDID.
> Use clk_round_rate() to validate the "ldb" clock rate for each mode
> in drm_bridge_funcs::mode_valid() to filter unsupported modes out.
> 
> Also, if the "ldb" clock and the pixel clock are sibling in clock
> tree, use clk_round_rate() to validate the pixel clock rate against
> the "ldb" clock.  This is not done in display controller driver
> because drm_crtc_helper_funcs::mode_valid() may not decide to do
> the validation or not if multiple encoders are connected to the CRTC,
> e.g., i.MX93 LCDIF may connect with MIPI DSI controller, LDB and
> parallel display output simultaneously.
> 
> Signed-off-by: Liu Ying <victor.liu@nxp.com>
> ---
>  drivers/gpu/drm/bridge/fsl-ldb.c | 22 ++++++++++++++++++++++
>  1 file changed, 22 insertions(+)
> 
> diff --git a/drivers/gpu/drm/bridge/fsl-ldb.c b/drivers/gpu/drm/bridge/fsl-ldb.c
> index b559f3e0bef6..ee8471c86617 100644
> --- a/drivers/gpu/drm/bridge/fsl-ldb.c
> +++ b/drivers/gpu/drm/bridge/fsl-ldb.c
> @@ -11,6 +11,7 @@
>  #include <linux/of_graph.h>
>  #include <linux/platform_device.h>
>  #include <linux/regmap.h>
> +#include <linux/units.h>
>  
>  #include <drm/drm_atomic_helper.h>
>  #include <drm/drm_bridge.h>
> @@ -64,6 +65,7 @@ struct fsl_ldb_devdata {
>  	u32 lvds_ctrl;
>  	bool lvds_en_bit;
>  	bool single_ctrl_reg;
> +	bool ldb_clk_pixel_clk_sibling;
>  };
>  
>  static const struct fsl_ldb_devdata fsl_ldb_devdata[] = {
> @@ -74,11 +76,13 @@ static const struct fsl_ldb_devdata fsl_ldb_devdata[] = {
>  	[IMX8MP_LDB] = {
>  		.ldb_ctrl = 0x5c,
>  		.lvds_ctrl = 0x128,
> +		.ldb_clk_pixel_clk_sibling = true,
>  	},
>  	[IMX93_LDB] = {
>  		.ldb_ctrl = 0x20,
>  		.lvds_ctrl = 0x24,
>  		.lvds_en_bit = true,
> +		.ldb_clk_pixel_clk_sibling = true,
>  	},
>  };
>  
> @@ -269,11 +273,29 @@ fsl_ldb_mode_valid(struct drm_bridge *bridge,
>  		   const struct drm_display_info *info,
>  		   const struct drm_display_mode *mode)
>  {
> +	unsigned long link_freq, pclk_rate, rounded_pclk_rate;
>  	struct fsl_ldb *fsl_ldb = to_fsl_ldb(bridge);
>  
>  	if (mode->clock > (fsl_ldb_is_dual(fsl_ldb) ? 160000 : 80000))
>  		return MODE_CLOCK_HIGH;
>  
> +	/* Validate "ldb" clock rate. */
> +	link_freq = fsl_ldb_link_frequency(fsl_ldb, mode->clock);
> +	if (link_freq != clk_round_rate(fsl_ldb->clk, link_freq))
> +		return MODE_NOCLOCK;
> +
> +	/*
> +	 * Use "ldb" clock to validate pixel clock rate,
> +	 * if the two clocks are sibling.
> +	 */
> +	if (fsl_ldb->devdata->ldb_clk_pixel_clk_sibling) {
> +		pclk_rate = mode->clock * HZ_PER_KHZ;
> +
> +		rounded_pclk_rate = clk_round_rate(fsl_ldb->clk, pclk_rate);
> +		if (rounded_pclk_rate != pclk_rate)
> +			return MODE_NOCLOCK;
> +	}
> +

I guess this is to workaround the fact that the parent rate would be
changed, and thus the sibling rate as well? This should be documented in
a comment if so.

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 273 bytes --]

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

* Re: [PATCH 4/8] drm/bridge: fsl-ldb: Use clk_round_rate() to validate "ldb" clock rate
  2024-09-30  7:31   ` Maxime Ripard
@ 2024-09-30  7:55     ` Liu Ying
  2024-10-11 11:06       ` Maxime Ripard
  0 siblings, 1 reply; 38+ messages in thread
From: Liu Ying @ 2024-09-30  7:55 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: dri-devel, devicetree, linux-kernel, imx, linux-arm-kernel,
	andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart, jonas,
	jernej.skrabec, maarten.lankhorst, tzimmermann, airlied, simona,
	robh, krzk+dt, conor+dt, shawnguo, s.hauer, kernel, festevam,
	catalin.marinas, will, quic_bjorande, geert+renesas,
	dmitry.baryshkov, arnd, nfraprado, o.rempel, y.moog

On 09/30/2024, Maxime Ripard wrote:
> On Mon, Sep 30, 2024 at 01:28:59PM GMT, Liu Ying wrote:
>> Multiple display modes could be read from a display device's EDID.
>> Use clk_round_rate() to validate the "ldb" clock rate for each mode
>> in drm_bridge_funcs::mode_valid() to filter unsupported modes out.
>>
>> Also, if the "ldb" clock and the pixel clock are sibling in clock
>> tree, use clk_round_rate() to validate the pixel clock rate against
>> the "ldb" clock.  This is not done in display controller driver
>> because drm_crtc_helper_funcs::mode_valid() may not decide to do
>> the validation or not if multiple encoders are connected to the CRTC,
>> e.g., i.MX93 LCDIF may connect with MIPI DSI controller, LDB and
>> parallel display output simultaneously.
>>
>> Signed-off-by: Liu Ying <victor.liu@nxp.com>
>> ---
>>  drivers/gpu/drm/bridge/fsl-ldb.c | 22 ++++++++++++++++++++++
>>  1 file changed, 22 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/bridge/fsl-ldb.c b/drivers/gpu/drm/bridge/fsl-ldb.c
>> index b559f3e0bef6..ee8471c86617 100644
>> --- a/drivers/gpu/drm/bridge/fsl-ldb.c
>> +++ b/drivers/gpu/drm/bridge/fsl-ldb.c
>> @@ -11,6 +11,7 @@
>>  #include <linux/of_graph.h>
>>  #include <linux/platform_device.h>
>>  #include <linux/regmap.h>
>> +#include <linux/units.h>
>>  
>>  #include <drm/drm_atomic_helper.h>
>>  #include <drm/drm_bridge.h>
>> @@ -64,6 +65,7 @@ struct fsl_ldb_devdata {
>>  	u32 lvds_ctrl;
>>  	bool lvds_en_bit;
>>  	bool single_ctrl_reg;
>> +	bool ldb_clk_pixel_clk_sibling;
>>  };
>>  
>>  static const struct fsl_ldb_devdata fsl_ldb_devdata[] = {
>> @@ -74,11 +76,13 @@ static const struct fsl_ldb_devdata fsl_ldb_devdata[] = {
>>  	[IMX8MP_LDB] = {
>>  		.ldb_ctrl = 0x5c,
>>  		.lvds_ctrl = 0x128,
>> +		.ldb_clk_pixel_clk_sibling = true,
>>  	},
>>  	[IMX93_LDB] = {
>>  		.ldb_ctrl = 0x20,
>>  		.lvds_ctrl = 0x24,
>>  		.lvds_en_bit = true,
>> +		.ldb_clk_pixel_clk_sibling = true,
>>  	},
>>  };
>>  
>> @@ -269,11 +273,29 @@ fsl_ldb_mode_valid(struct drm_bridge *bridge,
>>  		   const struct drm_display_info *info,
>>  		   const struct drm_display_mode *mode)
>>  {
>> +	unsigned long link_freq, pclk_rate, rounded_pclk_rate;
>>  	struct fsl_ldb *fsl_ldb = to_fsl_ldb(bridge);
>>  
>>  	if (mode->clock > (fsl_ldb_is_dual(fsl_ldb) ? 160000 : 80000))
>>  		return MODE_CLOCK_HIGH;
>>  
>> +	/* Validate "ldb" clock rate. */
>> +	link_freq = fsl_ldb_link_frequency(fsl_ldb, mode->clock);
>> +	if (link_freq != clk_round_rate(fsl_ldb->clk, link_freq))
>> +		return MODE_NOCLOCK;
>> +
>> +	/*
>> +	 * Use "ldb" clock to validate pixel clock rate,
>> +	 * if the two clocks are sibling.
>> +	 */
>> +	if (fsl_ldb->devdata->ldb_clk_pixel_clk_sibling) {
>> +		pclk_rate = mode->clock * HZ_PER_KHZ;
>> +
>> +		rounded_pclk_rate = clk_round_rate(fsl_ldb->clk, pclk_rate);
>> +		if (rounded_pclk_rate != pclk_rate)
>> +			return MODE_NOCLOCK;
>> +	}
>> +
> 
> I guess this is to workaround the fact that the parent rate would be
> changed, and thus the sibling rate as well? This should be documented in
> a comment if so.

This is to workaround the fact that the display controller driver
(lcdif_kms.c) cannot do the mode validation against pixel clock, as
the commit message mentions.

The parent clock is IMX8MP_VIDEO_PLL1_OUT and it's clock rate is not
supposed to be changed any more once IMX8MP_VIDEO_PLL1 clock rate is
set by using DT assigned-clock-rates property.  For i.MX8MP EVK, the
clock rate is assigned to 1039500000Hz in imx8mp.dtsi in media_blk_ctrl
node.

> 
> Maxime

-- 
Regards,
Liu Ying

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

* Re: [PATCH 6/8] drm/bridge: Add ITE IT6263 LVDS to HDMI converter
  2024-09-30  7:11   ` Maxime Ripard
@ 2024-09-30  8:44     ` Liu Ying
  0 siblings, 0 replies; 38+ messages in thread
From: Liu Ying @ 2024-09-30  8:44 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: dri-devel, devicetree, linux-kernel, imx, linux-arm-kernel,
	andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart, jonas,
	jernej.skrabec, maarten.lankhorst, tzimmermann, airlied, simona,
	robh, krzk+dt, conor+dt, shawnguo, s.hauer, kernel, festevam,
	catalin.marinas, will, quic_bjorande, geert+renesas,
	dmitry.baryshkov, arnd, nfraprado, o.rempel, y.moog

On 09/30/2024, Maxime Ripard wrote:
> Hi,

Hi,

> 
> On Mon, Sep 30, 2024 at 01:29:01PM GMT, Liu Ying wrote:
>> Add basic HDMI video output support. Currently, only RGB888 output
>> pixel format is supported.  At the LVDS input side, the driver
>> supports single LVDS link and dual LVDS links with "jeida-24" LVDS
>> mapping.
>>
>> Product link:
>> https://www.ite.com.tw/en/product/cate1/IT6263
>>
>> Signed-off-by: Liu Ying <victor.liu@nxp.com>
> 
> Generally speaking, you need to use the new HDMI bridge infrastructure.
> There's a lot of required things you're not dealing with here (such as
> infoframes)

I'll add AVI infoframe support in the next version.
My system doesn't wire up any audio line to IT6263, so I cannot
add audio infoframe.  I hope this is enough.

> 
> Also, you should add a MAINTAINERS entry

Ok, will add this.

> 
> Maxime

-- 
Regards,
Liu Ying


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

* RE: [PATCH 5/8] dt-bindings: display: bridge: Add ITE IT6263 LVDS to HDMI converter
  2024-09-30  5:29 ` [PATCH 5/8] dt-bindings: display: bridge: Add ITE IT6263 LVDS to HDMI converter Liu Ying
@ 2024-09-30  9:04   ` Biju Das
  2024-09-30  9:16     ` Liu Ying
  2024-09-30 13:18     ` Biju Das
  2024-10-02  0:02   ` Rob Herring
  1 sibling, 2 replies; 38+ messages in thread
From: Biju Das @ 2024-09-30  9:04 UTC (permalink / raw)
  To: Liu Ying, dri-devel@lists.freedesktop.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linux-arm-kernel@lists.infradead.org
  Cc: andrzej.hajda@intel.com, neil.armstrong@linaro.org,
	rfoss@kernel.org, laurent.pinchart, jonas@kwiboo.se,
	jernej.skrabec@gmail.com, maarten.lankhorst@linux.intel.com,
	mripard@kernel.org, tzimmermann@suse.de, airlied@gmail.com,
	simona@ffwll.ch, robh@kernel.org, krzk+dt@kernel.org,
	conor+dt@kernel.org, shawnguo@kernel.org, s.hauer@pengutronix.de,
	kernel@pengutronix.de, festevam@gmail.com,
	catalin.marinas@arm.com, will@kernel.org,
	quic_bjorande@quicinc.com, geert+renesas@glider.be,
	dmitry.baryshkov@linaro.org, arnd@arndb.de,
	nfraprado@collabora.com, o.rempel@pengutronix.de,
	y.moog@phytec.de

Hi Liu,

thanks for the patch.

> -----Original Message-----
> From: linux-arm-kernel <linux-arm-kernel-bounces@lists.infradead.org> On Behalf Of Liu Ying
> Sent: Monday, September 30, 2024 6:29 AM
> Subject: [PATCH 5/8] dt-bindings: display: bridge: Add ITE IT6263 LVDS to HDMI converter
> 
> Document ITE IT6263 LVDS to HDMI converter.
> 
> Product link:
> https://www.ite.com.tw/en/product/cate1/IT6263
> 
> Signed-off-by: Liu Ying <victor.liu@nxp.com>
> ---
>  .../bindings/display/bridge/ite,it6263.yaml   | 310 ++++++++++++++++++
>  1 file changed, 310 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml
> 
> diff --git a/Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml
> b/Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml
> new file mode 100644
> index 000000000000..97fb81e5bc4a
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml
> @@ -0,0 +1,310 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/display/bridge/ite,it6263.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: ITE IT6263 LVDS to HDMI converter
> +
> +maintainers:
> +  - Liu Ying <victor.liu@nxp.com>
> +
> +description: |
> +  The IT6263 is a high-performance single-chip De-SSC(De-Spread
> +Spectrum) LVDS
> +  to HDMI converter.  Combined with LVDS receiver and HDMI 1.4a
> +transmitter,
> +  the IT6263 supports LVDS input and HDMI 1.4 output by conversion function.
> +  The built-in LVDS receiver can support single-link and dual-link LVDS
> +inputs,
> +  and the built-in HDMI transmitter is fully compliant with HDMI
> +1.4a/3D, HDCP
> +  1.2 and backward compatible with DVI 1.0 specification.
> +
> +  The IT6263 also encodes and transmits up to 8 channels of I2S digital
> + audio,  with sampling rate up to 192KHz and sample size up to 24 bits.
> + In addition,  an S/PDIF input port takes in compressed audio of up to 192KHz frame rate.
> +
> +  The newly supported High-Bit Rate(HBR) audio by HDMI specifications
> + v1.3 is  provided by the IT6263 in two interfaces: the four I2S input
> + ports or the  S/PDIF input port.  With both interfaces the highest
> + possible HBR frame rate  is supported at up to 768KHz.
> +
> +properties:
> +  compatible:
> +    const: ite,it6263
> +
> +  reg:
> +    maxItems: 1
> +
> +  clocks:
> +    maxItems: 1
> +    description: audio master clock
> +
> +  clock-names:
> +    const: mclk
> +
> +  reset-gpios:
> +    maxItems: 1
> +
> +  ivdd-supply:
> +    description: 1.8V digital logic power
> +
> +  ovdd-supply:
> +    description: 3.3V I/O pin power
> +
> +  txavcc18-supply:
> +    description: 1.8V HDMI analog frontend power
> +
> +  txavcc33-supply:
> +    description: 3.3V HDMI analog frontend power
> +
> +  pvcc1-supply:
> +    description: 1.8V HDMI frontend core PLL power
> +
> +  pvcc2-supply:
> +    description: 1.8V HDMI frontend filter PLL power
> +
> +  avcc-supply:
> +    description: 3.3V LVDS frontend power
> +
> +  anvdd-supply:
> +    description: 1.8V LVDS frontend analog power
> +
> +  apvdd-supply:
> +    description: 1.8V LVDS frontend PLL power
> +
> +  "#sound-dai-cells":
> +    const: 0
> +
> +  ite,i2s-audio-fifo-sources:
> +    $ref: /schemas/types.yaml#/definitions/uint32-array
> +    minItems: 1
> +    maxItems: 4
> +    items:
> +      enum: [0, 1, 2, 3]
> +    description:
> +      Each array element indicates the pin number of an I2S serial data input
> +      line which is connected to an audio FIFO, from audio FIFO0 to FIFO3.
> +
> +  ite,rl-channel-swap-audio-sources:
> +    $ref: /schemas/types.yaml#/definitions/uint32-array
> +    minItems: 1
> +    maxItems: 4
> +    uniqueItems: true
> +    items:
> +      enum: [0, 1, 2, 3]
> +    description:
> +      Each array element indicates an audio source whose right channel and left
> +      channel are swapped by this converter. For I2S, the element is the pin
> +      number of an I2S serial data input line. For S/PDIF, the element is always
> +      0.
> +
> +  ports:
> +    $ref: /schemas/graph.yaml#/properties/ports
> +
> +    oneOf:
> +      - properties:
> +          port@0:
> +            $ref: /schemas/graph.yaml#/properties/port
> +            description: the first LVDS input link
> +
> +          port@1: false
> +
> +          port@2:
> +            $ref: /schemas/graph.yaml#/properties/port
> +            description: video port for the HDMI output
> +
> +          port@3:
> +            $ref: /schemas/graph.yaml#/properties/port
> +            description: sound input port
> +
> +        required:
> +          - port@0
> +          - port@2
> +
> +      - properties:
> +          port@0:
> +            $ref: /schemas/graph.yaml#/$defs/port-base
> +            unevaluatedProperties: false
> +            description: the first LVDS input link
> +
> +            properties:
> +              dual-lvds-odd-pixels:
> +                type: boolean
> +                description: the first sink port for odd pixels
> +
> +              dual-lvds-even-pixels:
> +                type: boolean
> +                description: the first sink port for even pixels
> +
> +            oneOf:
> +              - required: [dual-lvds-odd-pixels]
> +              - required: [dual-lvds-even-pixels]
> +
> +          port@1:
> +            $ref: /schemas/graph.yaml#/$defs/port-base
> +            unevaluatedProperties: false
> +            description: the second LVDS input link
> +
> +            properties:
> +              dual-lvds-even-pixels:
> +                type: boolean
> +                description: the second sink port for even pixels
> +
> +              dual-lvds-odd-pixels:
> +                type: boolean
> +                description: the second sink port for odd pixels
> +
> +            oneOf:
> +              - required: [dual-lvds-even-pixels]
> +              - required: [dual-lvds-odd-pixels]


> +
> +          port@2:
> +            $ref: /schemas/graph.yaml#/properties/port
> +            description: video port for the HDMI output
> +
> +          port@3:
> +            $ref: /schemas/graph.yaml#/properties/port
> +            description: sound input port

What about single lvds as device support it?

Cheers,
Biju

> +
> +        required:
> +          - port@0
> +          - port@1
> +          - port@2
> +
> +        allOf:
> +          - if:
> +              properties:
> +                port@0:
> +                  required:
> +                    - dual-lvds-odd-pixels
> +            then:
> +              properties:
> +                port@1:
> +                  properties:
> +                    dual-lvds-odd-pixels: false
> +
> +          - if:
> +              properties:
> +                port@0:
> +                  required:
> +                    - dual-lvds-even-pixels
> +            then:
> +              properties:
> +                port@1:
> +                  properties:
> +                    dual-lvds-even-pixels: false
> +
> +required:
> +  - compatible
> +  - reg
> +  - ivdd-supply
> +  - ovdd-supply
> +  - txavcc18-supply
> +  - txavcc33-supply
> +  - pvcc1-supply
> +  - pvcc2-supply
> +  - avcc-supply
> +  - anvdd-supply
> +  - apvdd-supply
> +  - ports
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    /* single-link LVDS input */
> +    #include <dt-bindings/gpio/gpio.h>
> +
> +    i2c {
> +        #address-cells = <1>;
> +        #size-cells = <0>;
> +
> +        hdmi@4c {
> +            compatible = "ite,it6263";
> +            reg = <0x4c>;
> +            reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
> +            ivdd-supply = <&reg_buck5>;
> +            ovdd-supply = <&reg_vext_3v3>;
> +            txavcc18-supply = <&reg_buck5>;
> +            txavcc33-supply = <&reg_vext_3v3>;
> +            pvcc1-supply = <&reg_buck5>;
> +            pvcc2-supply = <&reg_buck5>;
> +            avcc-supply = <&reg_vext_3v3>;
> +            anvdd-supply = <&reg_buck5>;
> +            apvdd-supply = <&reg_buck5>;
> +
> +            ports {
> +                #address-cells = <1>;
> +                #size-cells = <0>;
> +
> +                port@0 {
> +                    reg = <0>;
> +
> +                    it6263_lvds_link1: endpoint {
> +                        remote-endpoint = <&ldb_lvds_ch0>;
> +                    };
> +                };
> +
> +                port@2 {
> +                    reg = <2>;
> +
> +                    it6263_out: endpoint {
> +                        remote-endpoint = <&hdmi_in>;
> +                    };
> +                };
> +            };
> +        };
> +    };
> +
> +  - |
> +    /* dual-link LVDS input */
> +    #include <dt-bindings/gpio/gpio.h>
> +
> +    i2c {
> +        #address-cells = <1>;
> +        #size-cells = <0>;
> +
> +        hdmi@4c {
> +            compatible = "ite,it6263";
> +            reg = <0x4c>;
> +            reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
> +            ivdd-supply = <&reg_buck5>;
> +            ovdd-supply = <&reg_vext_3v3>;
> +            txavcc18-supply = <&reg_buck5>;
> +            txavcc33-supply = <&reg_vext_3v3>;
> +            pvcc1-supply = <&reg_buck5>;
> +            pvcc2-supply = <&reg_buck5>;
> +            avcc-supply = <&reg_vext_3v3>;
> +            anvdd-supply = <&reg_buck5>;
> +            apvdd-supply = <&reg_buck5>;
> +
> +            ports {
> +                #address-cells = <1>;
> +                #size-cells = <0>;
> +
> +                port@0 {
> +                    reg = <0>;
> +                    dual-lvds-odd-pixels;
> +
> +                    it6263_lvds_link1_dual: endpoint {
> +                        remote-endpoint = <&ldb_lvds_ch0>;
> +                    };
> +                };
> +
> +                port@1 {
> +                    reg = <1>;
> +                    dual-lvds-even-pixels;
> +
> +                    it6263_lvds_link2_dual: endpoint {
> +                        remote-endpoint = <&ldb_lvds_ch1>;
> +                    };
> +                };
> +
> +                port@2 {
> +                    reg = <2>;
> +
> +                    it6263_out_dual: endpoint {
> +                        remote-endpoint = <&hdmi_in>;
> +                    };
> +                };
> +            };
> +        };
> +    };
> --
> 2.34.1
> 


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

* Re: [PATCH 5/8] dt-bindings: display: bridge: Add ITE IT6263 LVDS to HDMI converter
  2024-09-30  9:04   ` Biju Das
@ 2024-09-30  9:16     ` Liu Ying
  2024-09-30  9:24       ` Biju Das
  2024-09-30 13:18     ` Biju Das
  1 sibling, 1 reply; 38+ messages in thread
From: Liu Ying @ 2024-09-30  9:16 UTC (permalink / raw)
  To: Biju Das, dri-devel@lists.freedesktop.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linux-arm-kernel@lists.infradead.org
  Cc: andrzej.hajda@intel.com, neil.armstrong@linaro.org,
	rfoss@kernel.org, laurent.pinchart, jonas@kwiboo.se,
	jernej.skrabec@gmail.com, maarten.lankhorst@linux.intel.com,
	mripard@kernel.org, tzimmermann@suse.de, airlied@gmail.com,
	simona@ffwll.ch, robh@kernel.org, krzk+dt@kernel.org,
	conor+dt@kernel.org, shawnguo@kernel.org, s.hauer@pengutronix.de,
	kernel@pengutronix.de, festevam@gmail.com,
	catalin.marinas@arm.com, will@kernel.org,
	quic_bjorande@quicinc.com, geert+renesas@glider.be,
	dmitry.baryshkov@linaro.org, arnd@arndb.de,
	nfraprado@collabora.com, o.rempel@pengutronix.de,
	y.moog@phytec.de

On 09/30/2024, Biju Das wrote:
> Hi Liu,

Hi Biju,

> 
> thanks for the patch.
> 
>> -----Original Message-----
>> From: linux-arm-kernel <linux-arm-kernel-bounces@lists.infradead.org> On Behalf Of Liu Ying
>> Sent: Monday, September 30, 2024 6:29 AM
>> Subject: [PATCH 5/8] dt-bindings: display: bridge: Add ITE IT6263 LVDS to HDMI converter
>>
>> Document ITE IT6263 LVDS to HDMI converter.
>>
>> Product link:
>> https://www.ite.com.tw/en/product/cate1/IT6263
>>
>> Signed-off-by: Liu Ying <victor.liu@nxp.com>
>> ---
>>  .../bindings/display/bridge/ite,it6263.yaml   | 310 ++++++++++++++++++
>>  1 file changed, 310 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml
>>
>> diff --git a/Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml
>> b/Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml
>> new file mode 100644
>> index 000000000000..97fb81e5bc4a
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml
>> @@ -0,0 +1,310 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/display/bridge/ite,it6263.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: ITE IT6263 LVDS to HDMI converter
>> +
>> +maintainers:
>> +  - Liu Ying <victor.liu@nxp.com>
>> +
>> +description: |
>> +  The IT6263 is a high-performance single-chip De-SSC(De-Spread
>> +Spectrum) LVDS
>> +  to HDMI converter.  Combined with LVDS receiver and HDMI 1.4a
>> +transmitter,
>> +  the IT6263 supports LVDS input and HDMI 1.4 output by conversion function.
>> +  The built-in LVDS receiver can support single-link and dual-link LVDS
>> +inputs,
>> +  and the built-in HDMI transmitter is fully compliant with HDMI
>> +1.4a/3D, HDCP
>> +  1.2 and backward compatible with DVI 1.0 specification.
>> +
>> +  The IT6263 also encodes and transmits up to 8 channels of I2S digital
>> + audio,  with sampling rate up to 192KHz and sample size up to 24 bits.
>> + In addition,  an S/PDIF input port takes in compressed audio of up to 192KHz frame rate.
>> +
>> +  The newly supported High-Bit Rate(HBR) audio by HDMI specifications
>> + v1.3 is  provided by the IT6263 in two interfaces: the four I2S input
>> + ports or the  S/PDIF input port.  With both interfaces the highest
>> + possible HBR frame rate  is supported at up to 768KHz.
>> +
>> +properties:
>> +  compatible:
>> +    const: ite,it6263
>> +
>> +  reg:
>> +    maxItems: 1
>> +
>> +  clocks:
>> +    maxItems: 1
>> +    description: audio master clock
>> +
>> +  clock-names:
>> +    const: mclk
>> +
>> +  reset-gpios:
>> +    maxItems: 1
>> +
>> +  ivdd-supply:
>> +    description: 1.8V digital logic power
>> +
>> +  ovdd-supply:
>> +    description: 3.3V I/O pin power
>> +
>> +  txavcc18-supply:
>> +    description: 1.8V HDMI analog frontend power
>> +
>> +  txavcc33-supply:
>> +    description: 3.3V HDMI analog frontend power
>> +
>> +  pvcc1-supply:
>> +    description: 1.8V HDMI frontend core PLL power
>> +
>> +  pvcc2-supply:
>> +    description: 1.8V HDMI frontend filter PLL power
>> +
>> +  avcc-supply:
>> +    description: 3.3V LVDS frontend power
>> +
>> +  anvdd-supply:
>> +    description: 1.8V LVDS frontend analog power
>> +
>> +  apvdd-supply:
>> +    description: 1.8V LVDS frontend PLL power
>> +
>> +  "#sound-dai-cells":
>> +    const: 0
>> +
>> +  ite,i2s-audio-fifo-sources:
>> +    $ref: /schemas/types.yaml#/definitions/uint32-array
>> +    minItems: 1
>> +    maxItems: 4
>> +    items:
>> +      enum: [0, 1, 2, 3]
>> +    description:
>> +      Each array element indicates the pin number of an I2S serial data input
>> +      line which is connected to an audio FIFO, from audio FIFO0 to FIFO3.
>> +
>> +  ite,rl-channel-swap-audio-sources:
>> +    $ref: /schemas/types.yaml#/definitions/uint32-array
>> +    minItems: 1
>> +    maxItems: 4
>> +    uniqueItems: true
>> +    items:
>> +      enum: [0, 1, 2, 3]
>> +    description:
>> +      Each array element indicates an audio source whose right channel and left
>> +      channel are swapped by this converter. For I2S, the element is the pin
>> +      number of an I2S serial data input line. For S/PDIF, the element is always
>> +      0.
>> +
>> +  ports:
>> +    $ref: /schemas/graph.yaml#/properties/ports
>> +
>> +    oneOf:
>> +      - properties:
>> +          port@0:
>> +            $ref: /schemas/graph.yaml#/properties/port
>> +            description: the first LVDS input link
>> +
>> +          port@1: false
>> +
>> +          port@2:
>> +            $ref: /schemas/graph.yaml#/properties/port
>> +            description: video port for the HDMI output
>> +
>> +          port@3:
>> +            $ref: /schemas/graph.yaml#/properties/port
>> +            description: sound input port
>> +
>> +        required:
>> +          - port@0
>> +          - port@2
>> +
>> +      - properties:
>> +          port@0:
>> +            $ref: /schemas/graph.yaml#/$defs/port-base
>> +            unevaluatedProperties: false
>> +            description: the first LVDS input link
>> +
>> +            properties:
>> +              dual-lvds-odd-pixels:
>> +                type: boolean
>> +                description: the first sink port for odd pixels
>> +
>> +              dual-lvds-even-pixels:
>> +                type: boolean
>> +                description: the first sink port for even pixels
>> +
>> +            oneOf:
>> +              - required: [dual-lvds-odd-pixels]
>> +              - required: [dual-lvds-even-pixels]
>> +
>> +          port@1:
>> +            $ref: /schemas/graph.yaml#/$defs/port-base
>> +            unevaluatedProperties: false
>> +            description: the second LVDS input link
>> +
>> +            properties:
>> +              dual-lvds-even-pixels:
>> +                type: boolean
>> +                description: the second sink port for even pixels
>> +
>> +              dual-lvds-odd-pixels:
>> +                type: boolean
>> +                description: the second sink port for odd pixels
>> +
>> +            oneOf:
>> +              - required: [dual-lvds-even-pixels]
>> +              - required: [dual-lvds-odd-pixels]
> 
> 
>> +
>> +          port@2:
>> +            $ref: /schemas/graph.yaml#/properties/port
>> +            description: video port for the HDMI output
>> +
>> +          port@3:
>> +            $ref: /schemas/graph.yaml#/properties/port
>> +            description: sound input port
> 
> What about single lvds as device support it?

The single LVDS link has already been documented in this binding doc.  
Please find the "properties" above where only "port@0" and "port@2"
are required.

imx8mp-evk-lvds0-imx-lvds-hdmi.dtso and imx8mp-evk-lvds1-imx-lvds-hdmi.dtso
added in patch 7 support the NXP adapter card with single LVDS link.

> 
> Cheers,
> Biju
> 
>> +
>> +        required:
>> +          - port@0
>> +          - port@1
>> +          - port@2
>> +
>> +        allOf:
>> +          - if:
>> +              properties:
>> +                port@0:
>> +                  required:
>> +                    - dual-lvds-odd-pixels
>> +            then:
>> +              properties:
>> +                port@1:
>> +                  properties:
>> +                    dual-lvds-odd-pixels: false
>> +
>> +          - if:
>> +              properties:
>> +                port@0:
>> +                  required:
>> +                    - dual-lvds-even-pixels
>> +            then:
>> +              properties:
>> +                port@1:
>> +                  properties:
>> +                    dual-lvds-even-pixels: false
>> +
>> +required:
>> +  - compatible
>> +  - reg
>> +  - ivdd-supply
>> +  - ovdd-supply
>> +  - txavcc18-supply
>> +  - txavcc33-supply
>> +  - pvcc1-supply
>> +  - pvcc2-supply
>> +  - avcc-supply
>> +  - anvdd-supply
>> +  - apvdd-supply
>> +  - ports
>> +
>> +additionalProperties: false
>> +
>> +examples:
>> +  - |
>> +    /* single-link LVDS input */
>> +    #include <dt-bindings/gpio/gpio.h>
>> +
>> +    i2c {
>> +        #address-cells = <1>;
>> +        #size-cells = <0>;
>> +
>> +        hdmi@4c {
>> +            compatible = "ite,it6263";
>> +            reg = <0x4c>;
>> +            reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
>> +            ivdd-supply = <&reg_buck5>;
>> +            ovdd-supply = <&reg_vext_3v3>;
>> +            txavcc18-supply = <&reg_buck5>;
>> +            txavcc33-supply = <&reg_vext_3v3>;
>> +            pvcc1-supply = <&reg_buck5>;
>> +            pvcc2-supply = <&reg_buck5>;
>> +            avcc-supply = <&reg_vext_3v3>;
>> +            anvdd-supply = <&reg_buck5>;
>> +            apvdd-supply = <&reg_buck5>;
>> +
>> +            ports {
>> +                #address-cells = <1>;
>> +                #size-cells = <0>;
>> +
>> +                port@0 {
>> +                    reg = <0>;
>> +
>> +                    it6263_lvds_link1: endpoint {
>> +                        remote-endpoint = <&ldb_lvds_ch0>;
>> +                    };
>> +                };
>> +
>> +                port@2 {
>> +                    reg = <2>;
>> +
>> +                    it6263_out: endpoint {
>> +                        remote-endpoint = <&hdmi_in>;
>> +                    };
>> +                };
>> +            };
>> +        };
>> +    };
>> +
>> +  - |
>> +    /* dual-link LVDS input */
>> +    #include <dt-bindings/gpio/gpio.h>
>> +
>> +    i2c {
>> +        #address-cells = <1>;
>> +        #size-cells = <0>;
>> +
>> +        hdmi@4c {
>> +            compatible = "ite,it6263";
>> +            reg = <0x4c>;
>> +            reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
>> +            ivdd-supply = <&reg_buck5>;
>> +            ovdd-supply = <&reg_vext_3v3>;
>> +            txavcc18-supply = <&reg_buck5>;
>> +            txavcc33-supply = <&reg_vext_3v3>;
>> +            pvcc1-supply = <&reg_buck5>;
>> +            pvcc2-supply = <&reg_buck5>;
>> +            avcc-supply = <&reg_vext_3v3>;
>> +            anvdd-supply = <&reg_buck5>;
>> +            apvdd-supply = <&reg_buck5>;
>> +
>> +            ports {
>> +                #address-cells = <1>;
>> +                #size-cells = <0>;
>> +
>> +                port@0 {
>> +                    reg = <0>;
>> +                    dual-lvds-odd-pixels;
>> +
>> +                    it6263_lvds_link1_dual: endpoint {
>> +                        remote-endpoint = <&ldb_lvds_ch0>;
>> +                    };
>> +                };
>> +
>> +                port@1 {
>> +                    reg = <1>;
>> +                    dual-lvds-even-pixels;
>> +
>> +                    it6263_lvds_link2_dual: endpoint {
>> +                        remote-endpoint = <&ldb_lvds_ch1>;
>> +                    };
>> +                };
>> +
>> +                port@2 {
>> +                    reg = <2>;
>> +
>> +                    it6263_out_dual: endpoint {
>> +                        remote-endpoint = <&hdmi_in>;
>> +                    };
>> +                };
>> +            };
>> +        };
>> +    };
>> --
>> 2.34.1
>>
> 

-- 
Regards,
Liu Ying


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

* RE: [PATCH 6/8] drm/bridge: Add ITE IT6263 LVDS to HDMI converter
  2024-09-30  5:29 ` [PATCH 6/8] drm/bridge: " Liu Ying
  2024-09-30  7:11   ` Maxime Ripard
@ 2024-09-30  9:16   ` Biju Das
  2024-09-30  9:40     ` Liu Ying
  2024-09-30 13:10     ` Biju Das
  2024-10-02 10:19   ` Biju Das
  2 siblings, 2 replies; 38+ messages in thread
From: Biju Das @ 2024-09-30  9:16 UTC (permalink / raw)
  To: Liu Ying, dri-devel@lists.freedesktop.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linux-arm-kernel@lists.infradead.org
  Cc: andrzej.hajda@intel.com, neil.armstrong@linaro.org,
	rfoss@kernel.org, laurent.pinchart, jonas@kwiboo.se,
	jernej.skrabec@gmail.com, maarten.lankhorst@linux.intel.com,
	mripard@kernel.org, tzimmermann@suse.de, airlied@gmail.com,
	simona@ffwll.ch, robh@kernel.org, krzk+dt@kernel.org,
	conor+dt@kernel.org, shawnguo@kernel.org, s.hauer@pengutronix.de,
	kernel@pengutronix.de, festevam@gmail.com,
	catalin.marinas@arm.com, will@kernel.org,
	quic_bjorande@quicinc.com, geert+renesas@glider.be,
	dmitry.baryshkov@linaro.org, arnd@arndb.de,
	nfraprado@collabora.com, o.rempel@pengutronix.de,
	y.moog@phytec.de

Hi Liu,

Thanks for the patch.

> -----Original Message-----
> From: linux-arm-kernel <linux-arm-kernel-bounces@lists.infradead.org> On Behalf Of Liu Ying
> Sent: Monday, September 30, 2024 6:29 AM
> Subject: [PATCH 6/8] drm/bridge: Add ITE IT6263 LVDS to HDMI converter
> 
> Add basic HDMI video output support. Currently, only RGB888 output pixel format is supported.  At the
> LVDS input side, the driver supports single LVDS link and dual LVDS links with "jeida-24" LVDS
> mapping.
> 
> Product link:
> https://www.ite.com.tw/en/product/cate1/IT6263
> 
> Signed-off-by: Liu Ying <victor.liu@nxp.com>
> ---
>  drivers/gpu/drm/bridge/Kconfig      |   8 +
>  drivers/gpu/drm/bridge/Makefile     |   1 +
>  drivers/gpu/drm/bridge/ite-it6263.c | 829 ++++++++++++++++++++++++++++
>  3 files changed, 838 insertions(+)
>  create mode 100644 drivers/gpu/drm/bridge/ite-it6263.c
> 
> diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index
> 3eb955333c80..93f99682a090 100644
> --- a/drivers/gpu/drm/bridge/Kconfig
> +++ b/drivers/gpu/drm/bridge/Kconfig
> @@ -90,6 +90,14 @@ config DRM_FSL_LDB
>  	help
>  	  Support for i.MX8MP DPI-to-LVDS on-SoC encoder.
> 
> +config DRM_ITE_IT6263
> +	tristate "ITE IT6263 LVDS/HDMI bridge"
> +	depends on OF
> +	select DRM_KMS_HELPER
> +	select REGMAP_I2C
> +	help
> +	  ITE IT6263 LVDS to HDMI bridge chip driver.
> +
>  config DRM_ITE_IT6505
>  	tristate "ITE IT6505 DisplayPort bridge"
>  	depends on OF
> diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index
> 7df87b582dca..f3776dd473fd 100644
> --- a/drivers/gpu/drm/bridge/Makefile
> +++ b/drivers/gpu/drm/bridge/Makefile
> @@ -6,6 +6,7 @@ obj-$(CONFIG_DRM_CHRONTEL_CH7033) += chrontel-ch7033.o
>  obj-$(CONFIG_DRM_CROS_EC_ANX7688) += cros-ec-anx7688.o
>  obj-$(CONFIG_DRM_DISPLAY_CONNECTOR) += display-connector.o
>  obj-$(CONFIG_DRM_FSL_LDB) += fsl-ldb.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
>  obj-$(CONFIG_DRM_LONTIUM_LT9211) += lontium-lt9211.o diff --git a/drivers/gpu/drm/bridge/ite-it6263.c
> b/drivers/gpu/drm/bridge/ite-it6263.c
> new file mode 100644
> index 000000000000..886588497bc1
> --- /dev/null
> +++ b/drivers/gpu/drm/bridge/ite-it6263.c
> @@ -0,0 +1,829 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright 2024 NXP
> + */
> +
> +#include <linux/bitfield.h>
> +#include <linux/bits.h>
> +#include <linux/delay.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/i2c.h>
> +#include <linux/media-bus-format.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/regmap.h>
> +#include <linux/regulator/consumer.h>
> +
> +#include <drm/drm_atomic.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_atomic_state_helper.h> #include <drm/drm_bridge.h>
> +#include <drm/drm_connector.h> #include <drm/drm_crtc.h> #include
> +<drm/drm_edid.h> #include <drm/drm_of.h> #include
> +<drm/drm_probe_helper.h>
> +
> +/*
> +-----------------------------------------------------------------------
> +------
> + * LVDS registers
> + */
> +
> +/* LVDS software reset registers */
> +#define LVDS_REG_05			0x05
> +#define  REG_SOFT_P_RST			BIT(1)
> +
> +/* LVDS system configuration registers */
> +/* 0x0b */
> +#define LVDS_REG_0B			0x0b
> +#define  REG_SSC_PCLK_RF		BIT(0)
> +#define  REG_LVDS_IN_SWAP		BIT(1)
> +
> +/* LVDS test pattern gen control registers */
> +/* 0x2c */
> +#define LVDS_REG_2C			0x2c
> +#define  REG_COL_DEP			GENMASK(1, 0)
> +#define  BIT8				FIELD_PREP(REG_COL_DEP, 2)
> +#define  OUT_MAP			BIT(4)
> +#define  JEIDA				0
> +#define  REG_DESSC_ENB			BIT(6)
> +#define  DMODE				BIT(7)
> +#define  DISO				BIT(7)
> +#define  SISO				0
> +
> +#define LVDS_REG_3C			0x3c
> +#define LVDS_REG_3F			0x3f
> +#define LVDS_REG_47			0x47
> +#define LVDS_REG_48			0x48
> +#define LVDS_REG_4F			0x4f
> +#define LVDS_REG_52			0x52
> +
> +/*
> +-----------------------------------------------------------------------
> +------
> + * HDMI registers are separated into three banks:
> + * 1) HDMI register common bank: 0x00 ~ 0x2f  */
> +
> +/* HDMI genernal registers */
> +#define HDMI_REG_SW_RST			0x04
> +#define  SOFTREF_RST			BIT(5)
> +#define  SOFTA_RST			BIT(4)
> +#define  SOFTV_RST			BIT(3)
> +#define  AUD_RST			BIT(2)
> +#define  HDCP_RST			BIT(0)
> +#define  HDMI_RST_ALL			(SOFTREF_RST | SOFTA_RST | SOFTV_RST | \
> +					 AUD_RST | HDCP_RST)
> +
> +#define HDMI_REG_SYS_STATUS		0x0e
> +#define  HPDETECT			BIT(6)
> +#define  TXVIDSTABLE			BIT(4)
> +
> +#define HDMI_REG_BANK_CTRL		0x0f
> +#define  REG_BANK_SEL			BIT(0)
> +
> +/* HDMI System DDC control registers */
> +#define HDMI_REG_DDC_MASTER_CTRL	0x10
> +#define  MASTER_SEL_HOST		BIT(0)
> +
> +#define HDMI_REG_DDC_HEADER		0x11
> +
> +#define HDMI_REG_DDC_REQOFF		0x12
> +#define HDMI_REG_DDC_REQCOUNT		0x13
> +#define HDMI_REG_DDC_EDIDSEG		0x14
> +
> +#define HDMI_REG_DDC_CMD		0x15
> +#define  DDC_CMD_EDID_READ		0x3
> +#define  DDC_CMD_FIFO_CLR		0x9
> +
> +#define HDMI_REG_DDC_STATUS		0x16
> +#define  DDC_DONE			BIT(7)
> +#define  DDC_NOACK			BIT(5)
> +#define  DDC_WAITBUS			BIT(4)
> +#define  DDC_ARBILOSE			BIT(3)
> +#define  DDC_ERROR			(DDC_NOACK | DDC_WAITBUS | DDC_ARBILOSE)
> +
> +#define HDMI_DDC_FIFO_BYTES		32
> +#define HDMI_REG_DDC_READFIFO		0x17
> +#define HDMI_REG_LVDS_PORT		0x1d /* LVDS input control I2C addr */
> +#define HDMI_REG_LVDS_PORT_EN		0x1e
> +#define LVDS_INPUT_CTRL_I2C_ADDR	0x33
> +
> +/*
> +-----------------------------------------------------------------------
> +------
> + * 2) HDMI register bank0: 0x30 ~ 0xff
> + */
> +
> +/* HDMI AFE registers */
> +#define HDMI_REG_AFE_DRV_CTRL		0x61
> +#define  AFE_DRV_PWD			BIT(5)
> +#define  AFE_DRV_RST			BIT(4)
> +
> +#define HDMI_REG_AFE_XP_CTRL		0x62
> +#define  AFE_XP_GAINBIT			BIT(7)
> +#define  AFE_XP_ER0			BIT(4)
> +#define  AFE_XP_RESETB			BIT(3)
> +
> +#define HDMI_REG_AFE_ISW_CTRL		0x63
> +
> +#define HDMI_REG_AFE_IP_CTRL		0x64
> +#define  AFE_IP_GAINBIT			BIT(7)
> +#define  AFE_IP_ER0			BIT(3)
> +#define  AFE_IP_RESETB			BIT(2)
> +
> +/* HDMI input data format registers */
> +#define HDMI_REG_INPUT_MODE		0x70
> +#define  IN_RGB				0x00
> +
> +/* HDMI general control registers */
> +#define HDMI_REG_HDMI_MODE		0xc0
> +#define  TX_HDMI_MODE			BIT(0)
> +
> +#define HDMI_REG_GCP			0xc1
> +#define  AVMUTE				BIT(0)
> +#define  HDMI_COLOR_DEPTH		GENMASK(6, 4)
> +#define  HDMI_COLOR_DEPTH_24		FIELD_PREP(HDMI_COLOR_DEPTH, 4)
> +
> +#define HDMI_REG_PKT_GENERAL_CTRL	0xc6
> +#define  ENABLE_PKT			BIT(0)
> +#define  REPEAT_PKT			BIT(1)
> +
> +/*
> +-----------------------------------------------------------------------
> +------
> + * 3) HDMI register bank1: 0x130 ~ 0x1ff (HDMI packet registers)  */
> +
> +/* AVI packet registers */
> +#define HDMI_REG_AVI_DB1		0x158
> +#define  AVI_DB1_COLOR_SPACE		GENMASK(6, 5)
> +#define  AVI_COLOR_SPACE_RGB		FIELD_PREP(AVI_DB1_COLOR_SPACE, 0)
> +
> +#define MAX_PIXEL_CLOCK_KHZ		150000
> +#define HIGH_PIXEL_CLOCK_KHZ		80000
> +
> +struct it6263 {
> +	struct device *dev;
> +	struct i2c_client *hdmi_i2c;
> +	struct i2c_client *lvds_i2c;
> +	struct regmap *hdmi_regmap;
> +	struct regmap *lvds_regmap;
> +	struct drm_bridge bridge;
> +	struct drm_bridge *next_bridge;
> +	struct drm_connector connector;
> +	struct gpio_desc *reset_gpio;
> +	bool lvds_dual_link;
> +	bool lvds_link12_swap;
> +};
> +
> +static inline struct it6263 *bridge_to_it6263(struct drm_bridge
> +*bridge) {
> +	return container_of(bridge, struct it6263, bridge); }
> +
> +static inline struct it6263 *connector_to_it6263(struct drm_connector
> +*conn) {
> +	return container_of(conn, struct it6263, connector); }
> +
> +static bool it6263_hdmi_writeable_reg(struct device *dev, unsigned int
> +reg) {
> +	switch (reg) {
> +	case HDMI_REG_SW_RST:
> +	case HDMI_REG_BANK_CTRL:
> +	case HDMI_REG_DDC_MASTER_CTRL:
> +	case HDMI_REG_DDC_HEADER:
> +	case HDMI_REG_DDC_REQOFF:
> +	case HDMI_REG_DDC_REQCOUNT:
> +	case HDMI_REG_DDC_EDIDSEG:
> +	case HDMI_REG_DDC_CMD:
> +	case HDMI_REG_LVDS_PORT:
> +	case HDMI_REG_LVDS_PORT_EN:
> +	case HDMI_REG_AFE_DRV_CTRL:
> +	case HDMI_REG_AFE_XP_CTRL:
> +	case HDMI_REG_AFE_ISW_CTRL:
> +	case HDMI_REG_AFE_IP_CTRL:
> +	case HDMI_REG_INPUT_MODE:
> +	case HDMI_REG_HDMI_MODE:
> +	case HDMI_REG_GCP:
> +	case HDMI_REG_PKT_GENERAL_CTRL:
> +	case HDMI_REG_AVI_DB1:
> +		return true;
> +	default:
> +		return false;
> +	}
> +}
> +
> +static bool it6263_hdmi_readable_reg(struct device *dev, unsigned int
> +reg) {
> +	if (it6263_hdmi_writeable_reg(dev, reg))
> +		return true;
> +
> +	switch (reg) {
> +	case HDMI_REG_SYS_STATUS:
> +	case HDMI_REG_DDC_STATUS:
> +	case HDMI_REG_DDC_READFIFO:
> +		return true;
> +	default:
> +		return false;
> +	}
> +}
> +
> +static bool it6263_hdmi_volatile_reg(struct device *dev, unsigned int
> +reg) {
> +	switch (reg) {
> +	case HDMI_REG_SW_RST:
> +	case HDMI_REG_SYS_STATUS:
> +	case HDMI_REG_DDC_STATUS:
> +	case HDMI_REG_DDC_READFIFO:
> +		return true;
> +	default:
> +		return false;
> +	}
> +}
> +
> +static const struct regmap_range_cfg it6263_hdmi_range_cfg = {
> +	.range_min = 0x00,
> +	.range_max = HDMI_REG_AVI_DB1,
> +	.selector_reg = HDMI_REG_BANK_CTRL,
> +	.selector_mask = REG_BANK_SEL,
> +	.selector_shift = 0,
> +	.window_start = 0x00,
> +	.window_len = 0x100,
> +};
> +
> +static const struct regmap_config it6263_hdmi_regmap_config = {
> +	.name = "it6263-hdmi",
> +	.reg_bits = 8,
> +	.val_bits = 8,
> +	.writeable_reg = it6263_hdmi_writeable_reg,
> +	.readable_reg = it6263_hdmi_readable_reg,
> +	.volatile_reg = it6263_hdmi_volatile_reg,
> +	.max_register = HDMI_REG_AVI_DB1,
> +	.ranges = &it6263_hdmi_range_cfg,
> +	.num_ranges = 1,
> +	.cache_type = REGCACHE_MAPLE,
> +};
> +
> +static bool it6263_lvds_writeable_reg(struct device *dev, unsigned int
> +reg) {
> +	switch (reg) {
> +	case LVDS_REG_05:
> +	case LVDS_REG_0B:
> +	case LVDS_REG_2C:
> +	case LVDS_REG_3C:
> +	case LVDS_REG_3F:
> +	case LVDS_REG_47:
> +	case LVDS_REG_48:
> +	case LVDS_REG_4F:
> +	case LVDS_REG_52:
> +		return true;
> +	default:
> +		return false;
> +	}
> +}
> +
> +static bool it6263_lvds_readable_reg(struct device *dev, unsigned int
> +reg) {
> +	return it6263_lvds_writeable_reg(dev, reg); }
> +
> +static bool it6263_lvds_volatile_reg(struct device *dev, unsigned int
> +reg) {
> +	return reg == LVDS_REG_05;
> +}
> +
> +static const struct regmap_config it6263_lvds_regmap_config = {
> +	.name = "it6263-lvds",
> +	.reg_bits = 8,
> +	.val_bits = 8,
> +	.writeable_reg = it6263_lvds_writeable_reg,
> +	.readable_reg = it6263_lvds_readable_reg,
> +	.volatile_reg = it6263_lvds_volatile_reg,
> +	.max_register = LVDS_REG_52,
> +	.cache_type = REGCACHE_MAPLE,
> +};
> +
> +static const char * const it6263_supplies[] = {
> +	"ivdd", "ovdd", "txavcc18", "txavcc33", "pvcc1", "pvcc2",
> +	"avcc", "anvdd", "apvdd"
> +};
> +
> +static int it6263_parse_dt(struct it6263 *it) {
> +	struct device *dev = it->dev;
> +	struct device_node *port0, *port1;
> +	int ret = 0;
> +
> +	it->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 2, 0);
> +	if (IS_ERR(it->next_bridge))
> +		return dev_err_probe(dev, PTR_ERR(it->next_bridge),
> +				     "failed to get next bridge\n");
> +
> +	port0 = of_graph_get_port_by_id(dev->of_node, 0);
> +	port1 = of_graph_get_port_by_id(dev->of_node, 1);
> +	if (port0 && port1) {
> +		if (of_property_read_bool(port0, "dual-lvds-even-pixels") &&
> +		    of_property_read_bool(port1, "dual-lvds-odd-pixels")) {
> +			it->lvds_dual_link = true;
> +			it->lvds_link12_swap = true;
> +		} else if (of_property_read_bool(port0, "dual-lvds-odd-pixels") &&
> +			   of_property_read_bool(port1, "dual-lvds-even-pixels")) {
> +			it->lvds_dual_link = true;
> +		}
> +
> +		if (!it->lvds_dual_link) {
> +			dev_err(dev,
> +				"failed to get LVDS dual link pixel order\n");
> +			ret = -EINVAL;
> +		}
> +	} else if (port1) {
> +		ret = -EINVAL;
> +		dev_err(dev, "single input LVDS port1 is not supported\n");

		Are you supporting single input LVDS port0??

> +	} else if (!port0) {
> +		ret = -EINVAL;
> +		dev_err(dev, "no input LVDS port\n");
> +	}
> +
> +	of_node_put(port0);
> +	of_node_put(port1);
> +
> +	return ret;
> +}
> +
> +static inline void it6263_reset(struct it6263 *it) {
> +	if (!it->reset_gpio)
> +		return;
> +
> +	gpiod_set_value_cansleep(it->reset_gpio, 0);
> +	fsleep(1000);
> +	gpiod_set_value_cansleep(it->reset_gpio, 1);
> +	/* The chip maker says the low pulse should be at least 40ms. */
> +	fsleep(40000);
> +	gpiod_set_value_cansleep(it->reset_gpio, 0);
> +	/* addtional time to wait the high voltage to be stable */
> +	fsleep(5000);

What about other resets ??

/* AFE PLL reset and  pclk reset */

> +}
> +
> +static inline int it6263_lvds_set_i2c_addr(struct it6263 *it) {
> +	int ret;
> +
> +	ret = regmap_write(it->hdmi_regmap, HDMI_REG_LVDS_PORT,
> +			   LVDS_INPUT_CTRL_I2C_ADDR << 1);
> +	if (ret)
> +		return ret;
> +
> +	return regmap_write(it->hdmi_regmap, HDMI_REG_LVDS_PORT_EN, BIT(0)); }
> +
> +static inline void it6263_lvds_reset(struct it6263 *it) {
> +	/* AFE PLL reset */
> +	regmap_write_bits(it->lvds_regmap, LVDS_REG_3C, BIT(0), 0x0);
> +	fsleep(1000);
> +	regmap_write_bits(it->lvds_regmap, LVDS_REG_3C, BIT(0), BIT(0));
> +
> +	/* software pixel clock domain reset */
> +	regmap_write_bits(it->lvds_regmap, LVDS_REG_05, REG_SOFT_P_RST,
> +			  REG_SOFT_P_RST);
> +	fsleep(1000);
> +	regmap_write_bits(it->lvds_regmap, LVDS_REG_05, REG_SOFT_P_RST, 0x0);
> +	fsleep(10000);
> +}
> +
> +static inline void it6263_lvds_set_interface(struct it6263 *it) {
> +	/* color depth */
> +	regmap_write_bits(it->lvds_regmap, LVDS_REG_2C, REG_COL_DEP, BIT8);
> +	/* output mapping */
> +	regmap_write_bits(it->lvds_regmap, LVDS_REG_2C, OUT_MAP, JEIDA);
> +
> +	if (it->lvds_dual_link) {
> +		regmap_write_bits(it->lvds_regmap, LVDS_REG_2C, DMODE, DISO);
> +		regmap_write_bits(it->lvds_regmap, LVDS_REG_52, BIT(1), BIT(1));
> +	} else {
> +		regmap_write_bits(it->lvds_regmap, LVDS_REG_2C, DMODE, SISO);
> +		regmap_write_bits(it->lvds_regmap, LVDS_REG_52, BIT(1), 0);
> +	}
> +}
> +
> +static inline void it6263_lvds_set_afe(struct it6263 *it) {
> +	regmap_write(it->lvds_regmap, LVDS_REG_3C, 0xaa);
> +	regmap_write(it->lvds_regmap, LVDS_REG_3F, 0x02);
> +	regmap_write(it->lvds_regmap, LVDS_REG_47, 0xaa);
> +	regmap_write(it->lvds_regmap, LVDS_REG_48, 0x02);
> +	regmap_write(it->lvds_regmap, LVDS_REG_4F, 0x11);
> +
> +	regmap_write_bits(it->lvds_regmap, LVDS_REG_0B, REG_SSC_PCLK_RF,
> +			  REG_SSC_PCLK_RF);
> +	regmap_write_bits(it->lvds_regmap, LVDS_REG_3C, 0x07, 0);
> +	regmap_write_bits(it->lvds_regmap, LVDS_REG_2C, REG_DESSC_ENB,
> +			  REG_DESSC_ENB);
> +}
> +
> +static inline void it6263_lvds_sys_cfg(struct it6263 *it) {
> +	regmap_write_bits(it->lvds_regmap, LVDS_REG_0B, REG_LVDS_IN_SWAP,
> +			  it->lvds_link12_swap ? REG_LVDS_IN_SWAP : 0); }
> +
> +static inline void it6263_lvds_config(struct it6263 *it) {
> +	it6263_lvds_reset(it);
> +	it6263_lvds_set_interface(it);
> +	it6263_lvds_set_afe(it);
> +	it6263_lvds_sys_cfg(it);
> +}
> +
> +static inline void it6263_hdmi_config(struct it6263 *it) {
> +	regmap_write(it->hdmi_regmap, HDMI_REG_SW_RST, HDMI_RST_ALL);
> +	regmap_write(it->hdmi_regmap, HDMI_REG_INPUT_MODE, IN_RGB);
> +	regmap_write_bits(it->hdmi_regmap, HDMI_REG_GCP, HDMI_COLOR_DEPTH,
> +			  HDMI_COLOR_DEPTH_24);
> +	regmap_write_bits(it->hdmi_regmap, HDMI_REG_AVI_DB1,
> +			  AVI_DB1_COLOR_SPACE, AVI_COLOR_SPACE_RGB); }
> +
> +static enum drm_connector_status it6263_detect(struct it6263 *it) {
> +	unsigned int val;
> +
> +	regmap_read(it->hdmi_regmap, HDMI_REG_SYS_STATUS, &val);
> +	if (val & HPDETECT)
> +		return connector_status_connected;
> +	else
> +		return connector_status_disconnected; }
> +
> +static enum drm_connector_status
> +it6263_connector_detect(struct drm_connector *connector, bool force) {
> +	struct it6263 *it = connector_to_it6263(connector);
> +
> +	return it6263_detect(it);
> +}
> +
> +static const struct drm_connector_funcs it6263_connector_funcs = {
> +	.detect = it6263_connector_detect,
> +	.fill_modes = drm_helper_probe_single_connector_modes,
> +	.destroy = drm_connector_cleanup,
> +	.reset = drm_atomic_helper_connector_reset,
> +	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> +	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> +};
> +
> +static int it6263_read_edid(void *data, u8 *buf, unsigned int block,
> +size_t len) {
> +	struct it6263 *it = data;
> +	struct regmap *regmap = it->hdmi_regmap;
> +	unsigned int start = (block % 2) * EDID_LENGTH;
> +	unsigned int segment = block >> 1;
> +	unsigned int count, val;
> +	int ret;
> +
> +	regmap_write(regmap, HDMI_REG_DDC_MASTER_CTRL, MASTER_SEL_HOST);
> +	regmap_write(regmap, HDMI_REG_DDC_HEADER, DDC_ADDR << 1);
> +	regmap_write(regmap, HDMI_REG_DDC_EDIDSEG, segment);
> +
> +	while (len) {
> +		/* clear DDC FIFO */
> +		regmap_write(regmap, HDMI_REG_DDC_CMD, DDC_CMD_FIFO_CLR);
> +
> +		ret = regmap_read_poll_timeout(regmap, HDMI_REG_DDC_STATUS,
> +					       val, val & DDC_DONE,
> +					       2000, 10000);
> +		if (ret) {
> +			dev_err(it->dev, "failed to clear DDC FIFO:%d\n", ret);
> +			return ret;
> +		}
> +
> +		count = len > HDMI_DDC_FIFO_BYTES ? HDMI_DDC_FIFO_BYTES : len;
> +
> +		/* fire the read command */
> +		regmap_write(regmap, HDMI_REG_DDC_REQOFF, start);
> +		regmap_write(regmap, HDMI_REG_DDC_REQCOUNT, count);
> +		regmap_write(regmap, HDMI_REG_DDC_CMD, DDC_CMD_EDID_READ);
> +
> +		start += count;
> +		len -= count;
> +
> +		ret = regmap_read_poll_timeout(regmap, HDMI_REG_DDC_STATUS, val,
> +					       val & (DDC_DONE | DDC_ERROR),
> +					       20000, 250000);
> +		if (ret && !(val & DDC_ERROR)) {
> +			dev_err(it->dev, "failed to read EDID:%d\n", ret);
> +			return ret;
> +		}
> +
> +		if (val & DDC_ERROR) {
> +			dev_err(it->dev, "DDC error\n");
> +			return -EIO;
> +		}
> +
> +		/* cache to buffer */
> +		for (; count > 0; count--) {
> +			regmap_read(regmap, HDMI_REG_DDC_READFIFO, &val);
> +			*(buf++) = val;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int it6263_connector_get_modes(struct drm_connector *connector)
> +{
> +	struct it6263 *it = connector_to_it6263(connector);
> +	const struct drm_edid *drm_edid;
> +	int count;
> +
> +	drm_edid = drm_edid_read_custom(connector, it6263_read_edid, it);
> +
> +	drm_edid_connector_update(connector, drm_edid);
> +	count = drm_edid_connector_add_modes(connector);
> +
> +	drm_edid_free(drm_edid);
> +
> +	return count;
> +}
> +
> +static const struct drm_connector_helper_funcs it6263_connector_helper_funcs = {
> +	.get_modes = it6263_connector_get_modes, };
> +
> +static int it6263_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 *mode = &crtc_state->adjusted_mode;
> +
> +	return mode->clock > MAX_PIXEL_CLOCK_KHZ ? -EINVAL : 0; }
> +
> +static void
> +it6263_bridge_atomic_disable(struct drm_bridge *bridge,
> +			     struct drm_bridge_state *old_bridge_state) {
> +	struct it6263 *it = bridge_to_it6263(bridge);
> +
> +	regmap_write_bits(it->hdmi_regmap, HDMI_REG_GCP, AVMUTE, AVMUTE);
> +	regmap_write(it->hdmi_regmap, HDMI_REG_PKT_GENERAL_CTRL, 0);
> +	regmap_write(it->hdmi_regmap, HDMI_REG_AFE_DRV_CTRL,
> +		     AFE_DRV_RST | AFE_DRV_PWD);
> +}
> +
> +static void
> +it6263_bridge_atomic_enable(struct drm_bridge *bridge,
> +			    struct drm_bridge_state *old_bridge_state) {
> +	struct drm_atomic_state *state = old_bridge_state->base.state;
> +	struct it6263 *it = bridge_to_it6263(bridge);
> +	const struct drm_crtc_state *crtc_state;
> +	struct regmap *regmap = it->hdmi_regmap;
> +	const struct drm_display_mode *mode;
> +	struct drm_connector *connector;
> +	bool is_stable = false;
> +	struct drm_crtc *crtc;
> +	unsigned int val;
> +	bool pclk_high;
> +	int i, ret;
> +
> +	connector = drm_atomic_get_new_connector_for_encoder(state,
> +							     bridge->encoder);
> +	crtc = drm_atomic_get_new_connector_state(state, connector)->crtc;
> +	crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
> +	mode = &crtc_state->adjusted_mode;
> +
> +	regmap_write(regmap, HDMI_REG_HDMI_MODE, TX_HDMI_MODE);
> +
> +	/* HDMI AFE setup */
> +	pclk_high = mode->clock > HIGH_PIXEL_CLOCK_KHZ ? true : false;
> +	regmap_write(regmap, HDMI_REG_AFE_DRV_CTRL, AFE_DRV_RST);
> +	if (pclk_high)
> +		regmap_write(regmap, HDMI_REG_AFE_XP_CTRL,
> +			     AFE_XP_GAINBIT | AFE_XP_RESETB);
> +	else
> +		regmap_write(regmap, HDMI_REG_AFE_XP_CTRL,
> +			     AFE_XP_ER0 | AFE_XP_RESETB);
> +	regmap_write(regmap, HDMI_REG_AFE_ISW_CTRL, 0x10);
> +	if (pclk_high)
> +		regmap_write(regmap, HDMI_REG_AFE_IP_CTRL,
> +			     AFE_IP_GAINBIT | AFE_IP_RESETB);
> +	else
> +		regmap_write(regmap, HDMI_REG_AFE_IP_CTRL,
> +			     AFE_IP_ER0 | AFE_IP_RESETB);
> +
> +	/* HDMI software video reset */
> +	regmap_write_bits(regmap, HDMI_REG_SW_RST, SOFTV_RST, SOFTV_RST);
> +	fsleep(1000);
> +	regmap_write_bits(regmap, HDMI_REG_SW_RST, SOFTV_RST, 0);
> +
> +	/* reconfigure LVDS and retry several times in case video is instable */
> +	for (i = 0; i < 3; i++) {
> +		ret = regmap_read_poll_timeout(regmap, HDMI_REG_SYS_STATUS, val,
> +					       val & TXVIDSTABLE,
> +					       20000, 500000);
> +		if (!ret) {
> +			is_stable = true;
> +			break;
> +		}
> +
> +		it6263_lvds_config(it);
> +	}
> +
> +	if (!is_stable)
> +		dev_warn(it->dev, "failed to wait for video stable\n");
> +
> +	/* HDMI AFE reset release and power up */
> +	regmap_write(regmap, HDMI_REG_AFE_DRV_CTRL, 0);
> +
> +	regmap_write_bits(regmap, HDMI_REG_GCP, AVMUTE, 0);
> +
> +	regmap_write(regmap, HDMI_REG_PKT_GENERAL_CTRL, ENABLE_PKT |
> +REPEAT_PKT); }
> +
> +static enum drm_mode_status
> +it6263_bridge_mode_valid(struct drm_bridge *bridge,
> +			 const struct drm_display_info *info,
> +			 const struct drm_display_mode *mode) {
> +	return mode->clock > MAX_PIXEL_CLOCK_KHZ ? MODE_CLOCK_HIGH : MODE_OK;
> +}
> +
> +static int it6263_bridge_attach(struct drm_bridge *bridge,
> +				enum drm_bridge_attach_flags flags) {
> +	struct it6263 *it = bridge_to_it6263(bridge);
> +	int ret;
> +
> +	ret = drm_bridge_attach(bridge->encoder, it->next_bridge, bridge,
> +				flags | DRM_BRIDGE_ATTACH_NO_CONNECTOR);
> +	if (ret < 0)
> +		return ret;
> +
> +	if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
> +		return 0;
> +
> +	it->connector.polled = DRM_CONNECTOR_POLL_CONNECT |
> +			       DRM_CONNECTOR_POLL_DISCONNECT;
> +
> +	ret = drm_connector_init(bridge->dev, &it->connector,
> +				 &it6263_connector_funcs,
> +				 DRM_MODE_CONNECTOR_HDMIA);
> +	if (ret)
> +		return ret;
> +
> +	drm_connector_helper_add(&it->connector,
> +				 &it6263_connector_helper_funcs);
> +	drm_connector_attach_encoder(&it->connector, bridge->encoder);
> +
> +	return 0;
> +}
> +
> +static enum drm_connector_status it6263_bridge_detect(struct drm_bridge
> +*bridge) {
> +	struct it6263 *it = bridge_to_it6263(bridge);
> +
> +	return it6263_detect(it);
> +}
> +
> +static const struct drm_edid *
> +it6263_bridge_edid_read(struct drm_bridge *bridge,
> +			struct drm_connector *connector)
> +{
> +	struct it6263 *it = bridge_to_it6263(bridge);
> +
> +	return drm_edid_read_custom(connector, it6263_read_edid, it); }
> +
> +static u32 *
> +it6263_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
> +					struct drm_bridge_state *bridge_state,
> +					struct drm_crtc_state *crtc_state,
> +					struct drm_connector_state *conn_state,
> +					u32 output_fmt,
> +					unsigned int *num_input_fmts)
> +{
> +	u32 *input_fmts;
> +
> +	input_fmts = kmalloc(sizeof(*input_fmts), GFP_KERNEL);
> +	if (!input_fmts) {
> +		*num_input_fmts = 0;
> +		return NULL;
> +	}
> +
> +	input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA;

Why is it hardcoded? What about supporting VESA??

> +	*num_input_fmts = 1;
> +
> +	return input_fmts;
> +}
> +
> +static const struct drm_bridge_funcs it6263_bridge_funcs = {
> +	.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,
> +	.attach = it6263_bridge_attach,
> +	.mode_valid = it6263_bridge_mode_valid,
> +	.atomic_disable = it6263_bridge_atomic_disable,
> +	.atomic_enable = it6263_bridge_atomic_enable,
> +	.atomic_check = it6263_bridge_atomic_check,
> +	.detect = it6263_bridge_detect,
> +	.edid_read = it6263_bridge_edid_read,
> +	.atomic_get_input_bus_fmts = it6263_bridge_atomic_get_input_bus_fmts,
> +};
> +
> +static int it6263_probe(struct i2c_client *client) {
> +	struct device *dev = &client->dev;
> +	struct it6263 *it;
> +	int ret;
> +
> +	it = devm_kzalloc(dev, sizeof(*it), GFP_KERNEL);
> +	if (!it)
> +		return -ENOMEM;
> +
> +	it->dev = dev;
> +	it->hdmi_i2c = client;
> +
> +	it->hdmi_regmap = devm_regmap_init_i2c(client,
> +					       &it6263_hdmi_regmap_config);
> +	if (IS_ERR(it->hdmi_regmap))
> +		return dev_err_probe(dev, PTR_ERR(it->hdmi_regmap),
> +				     "failed to init I2C regmap for HDMI\n");
> +
> +	it->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
> +	if (IS_ERR(it->reset_gpio))
> +		return dev_err_probe(dev, PTR_ERR(it->reset_gpio),
> +				     "failed to get reset gpio\n");
> +
> +	ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(it6263_supplies),
> +					     it6263_supplies);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "failed to get power supplies\n");
> +
> +	ret = it6263_parse_dt(it);
> +	if (ret)
> +		return ret;
> +
> +	it6263_reset(it);
> +
> +	ret = it6263_lvds_set_i2c_addr(it);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "failed to set I2C addr\n");
> +
> +	it->lvds_i2c = devm_i2c_new_dummy_device(dev, client->adapter,
> +						 LVDS_INPUT_CTRL_I2C_ADDR);
> +	if (IS_ERR(it->lvds_i2c))
> +		dev_err_probe(it->dev, PTR_ERR(it->lvds_i2c),
> +			      "failed to allocate I2C device for LVDS\n");

Maybe use action_or_reset and call i2c_unregister_device();

> +
> +	it->lvds_regmap = devm_regmap_init_i2c(it->lvds_i2c,
> +					       &it6263_lvds_regmap_config);
> +	if (IS_ERR(it->lvds_regmap))
> +		return dev_err_probe(dev, PTR_ERR(it->lvds_regmap),
> +				     "failed to init I2C regmap for LVDS\n");

> +
> +	it6263_lvds_config(it);
> +	it6263_hdmi_config(it);

> +
> +	i2c_set_clientdata(client, it);
> +
> +	it->bridge.funcs = &it6263_bridge_funcs;
> +	it->bridge.of_node = dev->of_node;
> +	it->bridge.ops = DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_DETECT;

	it->bridge.type = DRM_MODE_CONNECTOR_HDMIA; ??

> +	drm_bridge_add(&it->bridge);
> +
> +	return 0;
> +}
> +
> +static void it6263_remove(struct i2c_client *client) {
> +	struct it6263 *it = i2c_get_clientdata(client);
> +
> +	drm_bridge_remove(&it->bridge);

> +}
> +
> +static const struct of_device_id it6263_of_match[] = {
> +	{ .compatible = "ite,it6263", },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, it6263_of_match);
> +
> +static const struct i2c_device_id it6263_i2c_ids[] = {
> +	{ "it6263", 0 },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(i2c, it6263_i2c_ids);
> +
> +static struct i2c_driver it6263_driver = {
> +	.probe = it6263_probe,
> +	.remove = it6263_remove,
> +	.driver = {
> +		.name = "it6263",
> +		.of_match_table = it6263_of_match,
> +	},
> +	.id_table = it6263_i2c_ids,
> +};
> +module_i2c_driver(it6263_driver);
> +
> +MODULE_DESCRIPTION("ITE Tech. Inc. IT6263 LVDS/HDMI bridge");
> +MODULE_AUTHOR("Liu Ying <victor.liu@nxp.com>"); MODULE_LICENSE("GPL");
> --
> 2.34.1
> 


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

* RE: [PATCH 5/8] dt-bindings: display: bridge: Add ITE IT6263 LVDS to HDMI converter
  2024-09-30  9:16     ` Liu Ying
@ 2024-09-30  9:24       ` Biju Das
  2024-09-30  9:30         ` Liu Ying
  0 siblings, 1 reply; 38+ messages in thread
From: Biju Das @ 2024-09-30  9:24 UTC (permalink / raw)
  To: Liu Ying, dri-devel@lists.freedesktop.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linux-arm-kernel@lists.infradead.org
  Cc: andrzej.hajda@intel.com, neil.armstrong@linaro.org,
	rfoss@kernel.org, laurent.pinchart, jonas@kwiboo.se,
	jernej.skrabec@gmail.com, maarten.lankhorst@linux.intel.com,
	mripard@kernel.org, tzimmermann@suse.de, airlied@gmail.com,
	simona@ffwll.ch, robh@kernel.org, krzk+dt@kernel.org,
	conor+dt@kernel.org, shawnguo@kernel.org, s.hauer@pengutronix.de,
	kernel@pengutronix.de, festevam@gmail.com,
	catalin.marinas@arm.com, will@kernel.org,
	quic_bjorande@quicinc.com, geert+renesas@glider.be,
	dmitry.baryshkov@linaro.org, arnd@arndb.de,
	nfraprado@collabora.com, o.rempel@pengutronix.de,
	y.moog@phytec.de

Hi Liu,

> -----Original Message-----
> From: Liu Ying <victor.liu@nxp.com>
> Sent: Monday, September 30, 2024 10:16 AM
> Subject: Re: [PATCH 5/8] dt-bindings: display: bridge: Add ITE IT6263 LVDS to HDMI converter
> 
> On 09/30/2024, Biju Das wrote:
> > Hi Liu,
> 
> Hi Biju,
> 
> >
> > thanks for the patch.
> >
> >> -----Original Message-----
> >> From: linux-arm-kernel <linux-arm-kernel-bounces@lists.infradead.org>
> >> On Behalf Of Liu Ying
> >> Sent: Monday, September 30, 2024 6:29 AM
> >> Subject: [PATCH 5/8] dt-bindings: display: bridge: Add ITE IT6263
> >> LVDS to HDMI converter
> >>
> >> Document ITE IT6263 LVDS to HDMI converter.
> >>
> >> Product link:
> >> https://www.ite.com.tw/en/product/cate1/IT6263
> >>
> >> Signed-off-by: Liu Ying <victor.liu@nxp.com>
> >> ---
> >>  .../bindings/display/bridge/ite,it6263.yaml   | 310 ++++++++++++++++++
> >>  1 file changed, 310 insertions(+)
> >>  create mode 100644
> >> Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml
> >>
> >> diff --git
> >> a/Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml
> >> b/Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml
> >> new file mode 100644
> >> index 000000000000..97fb81e5bc4a
> >> --- /dev/null
> >> +++ b/Documentation/devicetree/bindings/display/bridge/ite,it6263.yam
> >> +++ l
> >> @@ -0,0 +1,310 @@
> >> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2
> >> +---
> >> +$id: http://devicetree.org/schemas/display/bridge/ite,it6263.yaml#
> >> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> >> +
> >> +title: ITE IT6263 LVDS to HDMI converter
> >> +
> >> +maintainers:
> >> +  - Liu Ying <victor.liu@nxp.com>
> >> +
> >> +description: |
> >> +  The IT6263 is a high-performance single-chip De-SSC(De-Spread
> >> +Spectrum) LVDS
> >> +  to HDMI converter.  Combined with LVDS receiver and HDMI 1.4a
> >> +transmitter,
> >> +  the IT6263 supports LVDS input and HDMI 1.4 output by conversion function.
> >> +  The built-in LVDS receiver can support single-link and dual-link
> >> +LVDS inputs,
> >> +  and the built-in HDMI transmitter is fully compliant with HDMI
> >> +1.4a/3D, HDCP
> >> +  1.2 and backward compatible with DVI 1.0 specification.
> >> +
> >> +  The IT6263 also encodes and transmits up to 8 channels of I2S
> >> + digital audio,  with sampling rate up to 192KHz and sample size up to 24 bits.
> >> + In addition,  an S/PDIF input port takes in compressed audio of up to 192KHz frame rate.
> >> +
> >> +  The newly supported High-Bit Rate(HBR) audio by HDMI
> >> + specifications
> >> + v1.3 is  provided by the IT6263 in two interfaces: the four I2S
> >> + input ports or the  S/PDIF input port.  With both interfaces the
> >> + highest possible HBR frame rate  is supported at up to 768KHz.
> >> +
> >> +properties:
> >> +  compatible:
> >> +    const: ite,it6263
> >> +
> >> +  reg:
> >> +    maxItems: 1
> >> +
> >> +  clocks:
> >> +    maxItems: 1
> >> +    description: audio master clock
> >> +
> >> +  clock-names:
> >> +    const: mclk
> >> +
> >> +  reset-gpios:
> >> +    maxItems: 1
> >> +
> >> +  ivdd-supply:
> >> +    description: 1.8V digital logic power
> >> +
> >> +  ovdd-supply:
> >> +    description: 3.3V I/O pin power
> >> +
> >> +  txavcc18-supply:
> >> +    description: 1.8V HDMI analog frontend power
> >> +
> >> +  txavcc33-supply:
> >> +    description: 3.3V HDMI analog frontend power
> >> +
> >> +  pvcc1-supply:
> >> +    description: 1.8V HDMI frontend core PLL power
> >> +
> >> +  pvcc2-supply:
> >> +    description: 1.8V HDMI frontend filter PLL power
> >> +
> >> +  avcc-supply:
> >> +    description: 3.3V LVDS frontend power
> >> +
> >> +  anvdd-supply:
> >> +    description: 1.8V LVDS frontend analog power
> >> +
> >> +  apvdd-supply:
> >> +    description: 1.8V LVDS frontend PLL power
> >> +
> >> +  "#sound-dai-cells":
> >> +    const: 0
> >> +
> >> +  ite,i2s-audio-fifo-sources:
> >> +    $ref: /schemas/types.yaml#/definitions/uint32-array
> >> +    minItems: 1
> >> +    maxItems: 4
> >> +    items:
> >> +      enum: [0, 1, 2, 3]
> >> +    description:
> >> +      Each array element indicates the pin number of an I2S serial data input
> >> +      line which is connected to an audio FIFO, from audio FIFO0 to FIFO3.
> >> +
> >> +  ite,rl-channel-swap-audio-sources:
> >> +    $ref: /schemas/types.yaml#/definitions/uint32-array
> >> +    minItems: 1
> >> +    maxItems: 4
> >> +    uniqueItems: true
> >> +    items:
> >> +      enum: [0, 1, 2, 3]
> >> +    description:
> >> +      Each array element indicates an audio source whose right channel and left
> >> +      channel are swapped by this converter. For I2S, the element is the pin
> >> +      number of an I2S serial data input line. For S/PDIF, the element is always
> >> +      0.
> >> +
> >> +  ports:
> >> +    $ref: /schemas/graph.yaml#/properties/ports
> >> +
> >> +    oneOf:
> >> +      - properties:
> >> +          port@0:
> >> +            $ref: /schemas/graph.yaml#/properties/port
> >> +            description: the first LVDS input link
> >> +
> >> +          port@1: false
> >> +
> >> +          port@2:
> >> +            $ref: /schemas/graph.yaml#/properties/port
> >> +            description: video port for the HDMI output
> >> +
> >> +          port@3:
> >> +            $ref: /schemas/graph.yaml#/properties/port
> >> +            description: sound input port
> >> +
> >> +        required:
> >> +          - port@0
> >> +          - port@2
> >> +
> >> +      - properties:
> >> +          port@0:
> >> +            $ref: /schemas/graph.yaml#/$defs/port-base
> >> +            unevaluatedProperties: false
> >> +            description: the first LVDS input link
> >> +
> >> +            properties:
> >> +              dual-lvds-odd-pixels:
> >> +                type: boolean
> >> +                description: the first sink port for odd pixels
> >> +
> >> +              dual-lvds-even-pixels:
> >> +                type: boolean
> >> +                description: the first sink port for even pixels
> >> +
> >> +            oneOf:
> >> +              - required: [dual-lvds-odd-pixels]
> >> +              - required: [dual-lvds-even-pixels]
> >> +
> >> +          port@1:
> >> +            $ref: /schemas/graph.yaml#/$defs/port-base
> >> +            unevaluatedProperties: false
> >> +            description: the second LVDS input link
> >> +
> >> +            properties:
> >> +              dual-lvds-even-pixels:
> >> +                type: boolean
> >> +                description: the second sink port for even pixels
> >> +
> >> +              dual-lvds-odd-pixels:
> >> +                type: boolean
> >> +                description: the second sink port for odd pixels
> >> +
> >> +            oneOf:
> >> +              - required: [dual-lvds-even-pixels]
> >> +              - required: [dual-lvds-odd-pixels]
> >
> >
> >> +
> >> +          port@2:
> >> +            $ref: /schemas/graph.yaml#/properties/port
> >> +            description: video port for the HDMI output
> >> +
> >> +          port@3:
> >> +            $ref: /schemas/graph.yaml#/properties/port
> >> +            description: sound input port
> >
> > What about single lvds as device support it?
> 
> The single LVDS link has already been documented in this binding doc.
> Please find the "properties" above where only "port@0" and "port@2"
> are required.

Maybe "the first LVDS input link"-->"Single LVDS input link" for single LVDS block??

> 
> imx8mp-evk-lvds0-imx-lvds-hdmi.dtso and imx8mp-evk-lvds1-imx-lvds-hdmi.dtso
> added in patch 7 support the NXP adapter card with single LVDS link.
> 
> >
> > Cheers,
> > Biju
> >
> >> +
> >> +        required:
> >> +          - port@0
> >> +          - port@1
> >> +          - port@2
> >> +
> >> +        allOf:
> >> +          - if:
> >> +              properties:
> >> +                port@0:
> >> +                  required:
> >> +                    - dual-lvds-odd-pixels
> >> +            then:
> >> +              properties:
> >> +                port@1:
> >> +                  properties:
> >> +                    dual-lvds-odd-pixels: false
> >> +
> >> +          - if:
> >> +              properties:
> >> +                port@0:
> >> +                  required:
> >> +                    - dual-lvds-even-pixels
> >> +            then:
> >> +              properties:
> >> +                port@1:
> >> +                  properties:
> >> +                    dual-lvds-even-pixels: false
> >> +
> >> +required:
> >> +  - compatible
> >> +  - reg
> >> +  - ivdd-supply
> >> +  - ovdd-supply
> >> +  - txavcc18-supply
> >> +  - txavcc33-supply
> >> +  - pvcc1-supply
> >> +  - pvcc2-supply
> >> +  - avcc-supply
> >> +  - anvdd-supply
> >> +  - apvdd-supply
> >> +  - ports
> >> +
> >> +additionalProperties: false
> >> +
> >> +examples:
> >> +  - |
> >> +    /* single-link LVDS input */
> >> +    #include <dt-bindings/gpio/gpio.h>
> >> +
> >> +    i2c {
> >> +        #address-cells = <1>;
> >> +        #size-cells = <0>;
> >> +
> >> +        hdmi@4c {
> >> +            compatible = "ite,it6263";
> >> +            reg = <0x4c>;
> >> +            reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
> >> +            ivdd-supply = <&reg_buck5>;
> >> +            ovdd-supply = <&reg_vext_3v3>;
> >> +            txavcc18-supply = <&reg_buck5>;
> >> +            txavcc33-supply = <&reg_vext_3v3>;
> >> +            pvcc1-supply = <&reg_buck5>;
> >> +            pvcc2-supply = <&reg_buck5>;
> >> +            avcc-supply = <&reg_vext_3v3>;
> >> +            anvdd-supply = <&reg_buck5>;
> >> +            apvdd-supply = <&reg_buck5>;
> >> +
> >> +            ports {
> >> +                #address-cells = <1>;
> >> +                #size-cells = <0>;
> >> +
> >> +                port@0 {
> >> +                    reg = <0>;
> >> +
> >> +                    it6263_lvds_link1: endpoint {
> >> +                        remote-endpoint = <&ldb_lvds_ch0>;
> >> +                    };
> >> +                };
> >> +
> >> +                port@2 {
> >> +                    reg = <2>;
> >> +
> >> +                    it6263_out: endpoint {
> >> +                        remote-endpoint = <&hdmi_in>;
> >> +                    };
> >> +                };
> >> +            };
> >> +        };
> >> +    };
> >> +
> >> +  - |
> >> +    /* dual-link LVDS input */
> >> +    #include <dt-bindings/gpio/gpio.h>
> >> +
> >> +    i2c {
> >> +        #address-cells = <1>;
> >> +        #size-cells = <0>;
> >> +
> >> +        hdmi@4c {
> >> +            compatible = "ite,it6263";
> >> +            reg = <0x4c>;
> >> +            reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
> >> +            ivdd-supply = <&reg_buck5>;
> >> +            ovdd-supply = <&reg_vext_3v3>;
> >> +            txavcc18-supply = <&reg_buck5>;
> >> +            txavcc33-supply = <&reg_vext_3v3>;
> >> +            pvcc1-supply = <&reg_buck5>;
> >> +            pvcc2-supply = <&reg_buck5>;
> >> +            avcc-supply = <&reg_vext_3v3>;
> >> +            anvdd-supply = <&reg_buck5>;
> >> +            apvdd-supply = <&reg_buck5>;
> >> +
> >> +            ports {
> >> +                #address-cells = <1>;
> >> +                #size-cells = <0>;
> >> +
> >> +                port@0 {
> >> +                    reg = <0>;
> >> +                    dual-lvds-odd-pixels;
> >> +
> >> +                    it6263_lvds_link1_dual: endpoint {
> >> +                        remote-endpoint = <&ldb_lvds_ch0>;
> >> +                    };
> >> +                };
> >> +
> >> +                port@1 {
> >> +                    reg = <1>;
> >> +                    dual-lvds-even-pixels;
> >> +
> >> +                    it6263_lvds_link2_dual: endpoint {
> >> +                        remote-endpoint = <&ldb_lvds_ch1>;
> >> +                    };
> >> +                };
> >> +
> >> +                port@2 {
> >> +                    reg = <2>;
> >> +
> >> +                    it6263_out_dual: endpoint {
> >> +                        remote-endpoint = <&hdmi_in>;
> >> +                    };
> >> +                };
> >> +            };
> >> +        };
> >> +    };
> >> --
> >> 2.34.1
> >>
> >
> 
> --
> Regards,
> Liu Ying


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

* Re: [PATCH 5/8] dt-bindings: display: bridge: Add ITE IT6263 LVDS to HDMI converter
  2024-09-30  9:24       ` Biju Das
@ 2024-09-30  9:30         ` Liu Ying
  2024-09-30  9:38           ` Biju Das
  0 siblings, 1 reply; 38+ messages in thread
From: Liu Ying @ 2024-09-30  9:30 UTC (permalink / raw)
  To: Biju Das, dri-devel@lists.freedesktop.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linux-arm-kernel@lists.infradead.org
  Cc: andrzej.hajda@intel.com, neil.armstrong@linaro.org,
	rfoss@kernel.org, laurent.pinchart, jonas@kwiboo.se,
	jernej.skrabec@gmail.com, maarten.lankhorst@linux.intel.com,
	mripard@kernel.org, tzimmermann@suse.de, airlied@gmail.com,
	simona@ffwll.ch, robh@kernel.org, krzk+dt@kernel.org,
	conor+dt@kernel.org, shawnguo@kernel.org, s.hauer@pengutronix.de,
	kernel@pengutronix.de, festevam@gmail.com,
	catalin.marinas@arm.com, will@kernel.org,
	quic_bjorande@quicinc.com, geert+renesas@glider.be,
	dmitry.baryshkov@linaro.org, arnd@arndb.de,
	nfraprado@collabora.com, o.rempel@pengutronix.de,
	y.moog@phytec.de

On 09/30/2024, Biju Das wrote:
> Hi Liu,

Hi Biju,

> 
>> -----Original Message-----
>> From: Liu Ying <victor.liu@nxp.com>
>> Sent: Monday, September 30, 2024 10:16 AM
>> Subject: Re: [PATCH 5/8] dt-bindings: display: bridge: Add ITE IT6263 LVDS to HDMI converter
>>
>> On 09/30/2024, Biju Das wrote:
>>> Hi Liu,
>>
>> Hi Biju,
>>
>>>
>>> thanks for the patch.
>>>
>>>> -----Original Message-----
>>>> From: linux-arm-kernel <linux-arm-kernel-bounces@lists.infradead.org>
>>>> On Behalf Of Liu Ying
>>>> Sent: Monday, September 30, 2024 6:29 AM
>>>> Subject: [PATCH 5/8] dt-bindings: display: bridge: Add ITE IT6263
>>>> LVDS to HDMI converter
>>>>
>>>> Document ITE IT6263 LVDS to HDMI converter.
>>>>
>>>> Product link:
>>>> https://www.ite.com.tw/en/product/cate1/IT6263
>>>>
>>>> Signed-off-by: Liu Ying <victor.liu@nxp.com>
>>>> ---
>>>>  .../bindings/display/bridge/ite,it6263.yaml   | 310 ++++++++++++++++++
>>>>  1 file changed, 310 insertions(+)
>>>>  create mode 100644
>>>> Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml
>>>>
>>>> diff --git
>>>> a/Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml
>>>> b/Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml
>>>> new file mode 100644
>>>> index 000000000000..97fb81e5bc4a
>>>> --- /dev/null
>>>> +++ b/Documentation/devicetree/bindings/display/bridge/ite,it6263.yam
>>>> +++ l
>>>> @@ -0,0 +1,310 @@
>>>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2
>>>> +---
>>>> +$id: http://devicetree.org/schemas/display/bridge/ite,it6263.yaml#
>>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>>> +
>>>> +title: ITE IT6263 LVDS to HDMI converter
>>>> +
>>>> +maintainers:
>>>> +  - Liu Ying <victor.liu@nxp.com>
>>>> +
>>>> +description: |
>>>> +  The IT6263 is a high-performance single-chip De-SSC(De-Spread
>>>> +Spectrum) LVDS
>>>> +  to HDMI converter.  Combined with LVDS receiver and HDMI 1.4a
>>>> +transmitter,
>>>> +  the IT6263 supports LVDS input and HDMI 1.4 output by conversion function.
>>>> +  The built-in LVDS receiver can support single-link and dual-link
>>>> +LVDS inputs,
>>>> +  and the built-in HDMI transmitter is fully compliant with HDMI
>>>> +1.4a/3D, HDCP
>>>> +  1.2 and backward compatible with DVI 1.0 specification.
>>>> +
>>>> +  The IT6263 also encodes and transmits up to 8 channels of I2S
>>>> + digital audio,  with sampling rate up to 192KHz and sample size up to 24 bits.
>>>> + In addition,  an S/PDIF input port takes in compressed audio of up to 192KHz frame rate.
>>>> +
>>>> +  The newly supported High-Bit Rate(HBR) audio by HDMI
>>>> + specifications
>>>> + v1.3 is  provided by the IT6263 in two interfaces: the four I2S
>>>> + input ports or the  S/PDIF input port.  With both interfaces the
>>>> + highest possible HBR frame rate  is supported at up to 768KHz.
>>>> +
>>>> +properties:
>>>> +  compatible:
>>>> +    const: ite,it6263
>>>> +
>>>> +  reg:
>>>> +    maxItems: 1
>>>> +
>>>> +  clocks:
>>>> +    maxItems: 1
>>>> +    description: audio master clock
>>>> +
>>>> +  clock-names:
>>>> +    const: mclk
>>>> +
>>>> +  reset-gpios:
>>>> +    maxItems: 1
>>>> +
>>>> +  ivdd-supply:
>>>> +    description: 1.8V digital logic power
>>>> +
>>>> +  ovdd-supply:
>>>> +    description: 3.3V I/O pin power
>>>> +
>>>> +  txavcc18-supply:
>>>> +    description: 1.8V HDMI analog frontend power
>>>> +
>>>> +  txavcc33-supply:
>>>> +    description: 3.3V HDMI analog frontend power
>>>> +
>>>> +  pvcc1-supply:
>>>> +    description: 1.8V HDMI frontend core PLL power
>>>> +
>>>> +  pvcc2-supply:
>>>> +    description: 1.8V HDMI frontend filter PLL power
>>>> +
>>>> +  avcc-supply:
>>>> +    description: 3.3V LVDS frontend power
>>>> +
>>>> +  anvdd-supply:
>>>> +    description: 1.8V LVDS frontend analog power
>>>> +
>>>> +  apvdd-supply:
>>>> +    description: 1.8V LVDS frontend PLL power
>>>> +
>>>> +  "#sound-dai-cells":
>>>> +    const: 0
>>>> +
>>>> +  ite,i2s-audio-fifo-sources:
>>>> +    $ref: /schemas/types.yaml#/definitions/uint32-array
>>>> +    minItems: 1
>>>> +    maxItems: 4
>>>> +    items:
>>>> +      enum: [0, 1, 2, 3]
>>>> +    description:
>>>> +      Each array element indicates the pin number of an I2S serial data input
>>>> +      line which is connected to an audio FIFO, from audio FIFO0 to FIFO3.
>>>> +
>>>> +  ite,rl-channel-swap-audio-sources:
>>>> +    $ref: /schemas/types.yaml#/definitions/uint32-array
>>>> +    minItems: 1
>>>> +    maxItems: 4
>>>> +    uniqueItems: true
>>>> +    items:
>>>> +      enum: [0, 1, 2, 3]
>>>> +    description:
>>>> +      Each array element indicates an audio source whose right channel and left
>>>> +      channel are swapped by this converter. For I2S, the element is the pin
>>>> +      number of an I2S serial data input line. For S/PDIF, the element is always
>>>> +      0.
>>>> +
>>>> +  ports:
>>>> +    $ref: /schemas/graph.yaml#/properties/ports
>>>> +
>>>> +    oneOf:
>>>> +      - properties:
>>>> +          port@0:
>>>> +            $ref: /schemas/graph.yaml#/properties/port
>>>> +            description: the first LVDS input link
>>>> +
>>>> +          port@1: false
>>>> +
>>>> +          port@2:
>>>> +            $ref: /schemas/graph.yaml#/properties/port
>>>> +            description: video port for the HDMI output
>>>> +
>>>> +          port@3:
>>>> +            $ref: /schemas/graph.yaml#/properties/port
>>>> +            description: sound input port
>>>> +
>>>> +        required:
>>>> +          - port@0
>>>> +          - port@2
>>>> +
>>>> +      - properties:
>>>> +          port@0:
>>>> +            $ref: /schemas/graph.yaml#/$defs/port-base
>>>> +            unevaluatedProperties: false
>>>> +            description: the first LVDS input link
>>>> +
>>>> +            properties:
>>>> +              dual-lvds-odd-pixels:
>>>> +                type: boolean
>>>> +                description: the first sink port for odd pixels
>>>> +
>>>> +              dual-lvds-even-pixels:
>>>> +                type: boolean
>>>> +                description: the first sink port for even pixels
>>>> +
>>>> +            oneOf:
>>>> +              - required: [dual-lvds-odd-pixels]
>>>> +              - required: [dual-lvds-even-pixels]
>>>> +
>>>> +          port@1:
>>>> +            $ref: /schemas/graph.yaml#/$defs/port-base
>>>> +            unevaluatedProperties: false
>>>> +            description: the second LVDS input link
>>>> +
>>>> +            properties:
>>>> +              dual-lvds-even-pixels:
>>>> +                type: boolean
>>>> +                description: the second sink port for even pixels
>>>> +
>>>> +              dual-lvds-odd-pixels:
>>>> +                type: boolean
>>>> +                description: the second sink port for odd pixels
>>>> +
>>>> +            oneOf:
>>>> +              - required: [dual-lvds-even-pixels]
>>>> +              - required: [dual-lvds-odd-pixels]
>>>
>>>
>>>> +
>>>> +          port@2:
>>>> +            $ref: /schemas/graph.yaml#/properties/port
>>>> +            description: video port for the HDMI output
>>>> +
>>>> +          port@3:
>>>> +            $ref: /schemas/graph.yaml#/properties/port
>>>> +            description: sound input port
>>>
>>> What about single lvds as device support it?
>>
>> The single LVDS link has already been documented in this binding doc.
>> Please find the "properties" above where only "port@0" and "port@2"
>> are required.
> 
> Maybe "the first LVDS input link"-->"Single LVDS input link" for single LVDS block??

Nope.

I tested single LVDS link with the second LVDS link.  It didn't work.
The single LVDS link only works with the first LVDS link.

> 
>>
>> imx8mp-evk-lvds0-imx-lvds-hdmi.dtso and imx8mp-evk-lvds1-imx-lvds-hdmi.dtso
>> added in patch 7 support the NXP adapter card with single LVDS link.
>>
>>>
>>> Cheers,
>>> Biju
>>>
>>>> +
>>>> +        required:
>>>> +          - port@0
>>>> +          - port@1
>>>> +          - port@2
>>>> +
>>>> +        allOf:
>>>> +          - if:
>>>> +              properties:
>>>> +                port@0:
>>>> +                  required:
>>>> +                    - dual-lvds-odd-pixels
>>>> +            then:
>>>> +              properties:
>>>> +                port@1:
>>>> +                  properties:
>>>> +                    dual-lvds-odd-pixels: false
>>>> +
>>>> +          - if:
>>>> +              properties:
>>>> +                port@0:
>>>> +                  required:
>>>> +                    - dual-lvds-even-pixels
>>>> +            then:
>>>> +              properties:
>>>> +                port@1:
>>>> +                  properties:
>>>> +                    dual-lvds-even-pixels: false
>>>> +
>>>> +required:
>>>> +  - compatible
>>>> +  - reg
>>>> +  - ivdd-supply
>>>> +  - ovdd-supply
>>>> +  - txavcc18-supply
>>>> +  - txavcc33-supply
>>>> +  - pvcc1-supply
>>>> +  - pvcc2-supply
>>>> +  - avcc-supply
>>>> +  - anvdd-supply
>>>> +  - apvdd-supply
>>>> +  - ports
>>>> +
>>>> +additionalProperties: false
>>>> +
>>>> +examples:
>>>> +  - |
>>>> +    /* single-link LVDS input */
>>>> +    #include <dt-bindings/gpio/gpio.h>
>>>> +
>>>> +    i2c {
>>>> +        #address-cells = <1>;
>>>> +        #size-cells = <0>;
>>>> +
>>>> +        hdmi@4c {
>>>> +            compatible = "ite,it6263";
>>>> +            reg = <0x4c>;
>>>> +            reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
>>>> +            ivdd-supply = <&reg_buck5>;
>>>> +            ovdd-supply = <&reg_vext_3v3>;
>>>> +            txavcc18-supply = <&reg_buck5>;
>>>> +            txavcc33-supply = <&reg_vext_3v3>;
>>>> +            pvcc1-supply = <&reg_buck5>;
>>>> +            pvcc2-supply = <&reg_buck5>;
>>>> +            avcc-supply = <&reg_vext_3v3>;
>>>> +            anvdd-supply = <&reg_buck5>;
>>>> +            apvdd-supply = <&reg_buck5>;
>>>> +
>>>> +            ports {
>>>> +                #address-cells = <1>;
>>>> +                #size-cells = <0>;
>>>> +
>>>> +                port@0 {
>>>> +                    reg = <0>;
>>>> +
>>>> +                    it6263_lvds_link1: endpoint {
>>>> +                        remote-endpoint = <&ldb_lvds_ch0>;
>>>> +                    };
>>>> +                };
>>>> +
>>>> +                port@2 {
>>>> +                    reg = <2>;
>>>> +
>>>> +                    it6263_out: endpoint {
>>>> +                        remote-endpoint = <&hdmi_in>;
>>>> +                    };
>>>> +                };
>>>> +            };
>>>> +        };
>>>> +    };
>>>> +
>>>> +  - |
>>>> +    /* dual-link LVDS input */
>>>> +    #include <dt-bindings/gpio/gpio.h>
>>>> +
>>>> +    i2c {
>>>> +        #address-cells = <1>;
>>>> +        #size-cells = <0>;
>>>> +
>>>> +        hdmi@4c {
>>>> +            compatible = "ite,it6263";
>>>> +            reg = <0x4c>;
>>>> +            reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
>>>> +            ivdd-supply = <&reg_buck5>;
>>>> +            ovdd-supply = <&reg_vext_3v3>;
>>>> +            txavcc18-supply = <&reg_buck5>;
>>>> +            txavcc33-supply = <&reg_vext_3v3>;
>>>> +            pvcc1-supply = <&reg_buck5>;
>>>> +            pvcc2-supply = <&reg_buck5>;
>>>> +            avcc-supply = <&reg_vext_3v3>;
>>>> +            anvdd-supply = <&reg_buck5>;
>>>> +            apvdd-supply = <&reg_buck5>;
>>>> +
>>>> +            ports {
>>>> +                #address-cells = <1>;
>>>> +                #size-cells = <0>;
>>>> +
>>>> +                port@0 {
>>>> +                    reg = <0>;
>>>> +                    dual-lvds-odd-pixels;
>>>> +
>>>> +                    it6263_lvds_link1_dual: endpoint {
>>>> +                        remote-endpoint = <&ldb_lvds_ch0>;
>>>> +                    };
>>>> +                };
>>>> +
>>>> +                port@1 {
>>>> +                    reg = <1>;
>>>> +                    dual-lvds-even-pixels;
>>>> +
>>>> +                    it6263_lvds_link2_dual: endpoint {
>>>> +                        remote-endpoint = <&ldb_lvds_ch1>;
>>>> +                    };
>>>> +                };
>>>> +
>>>> +                port@2 {
>>>> +                    reg = <2>;
>>>> +
>>>> +                    it6263_out_dual: endpoint {
>>>> +                        remote-endpoint = <&hdmi_in>;
>>>> +                    };
>>>> +                };
>>>> +            };
>>>> +        };
>>>> +    };
>>>> --
>>>> 2.34.1
>>>>
>>>
>>
>> --
>> Regards,
>> Liu Ying
> 

-- 
Regards,
Liu Ying


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

* RE: [PATCH 5/8] dt-bindings: display: bridge: Add ITE IT6263 LVDS to HDMI converter
  2024-09-30  9:30         ` Liu Ying
@ 2024-09-30  9:38           ` Biju Das
  2024-09-30  9:48             ` Liu Ying
  0 siblings, 1 reply; 38+ messages in thread
From: Biju Das @ 2024-09-30  9:38 UTC (permalink / raw)
  To: Liu Ying, dri-devel@lists.freedesktop.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linux-arm-kernel@lists.infradead.org
  Cc: andrzej.hajda@intel.com, neil.armstrong@linaro.org,
	rfoss@kernel.org, laurent.pinchart, jonas@kwiboo.se,
	jernej.skrabec@gmail.com, maarten.lankhorst@linux.intel.com,
	mripard@kernel.org, tzimmermann@suse.de, airlied@gmail.com,
	simona@ffwll.ch, robh@kernel.org, krzk+dt@kernel.org,
	conor+dt@kernel.org, shawnguo@kernel.org, s.hauer@pengutronix.de,
	kernel@pengutronix.de, festevam@gmail.com,
	catalin.marinas@arm.com, will@kernel.org,
	quic_bjorande@quicinc.com, geert+renesas@glider.be,
	dmitry.baryshkov@linaro.org, arnd@arndb.de,
	nfraprado@collabora.com, o.rempel@pengutronix.de,
	y.moog@phytec.de

Hi Liu,

> -----Original Message-----
> From: Liu Ying <victor.liu@nxp.com>
> Sent: Monday, September 30, 2024 10:30 AM
> Subject: Re: [PATCH 5/8] dt-bindings: display: bridge: Add ITE IT6263 LVDS to HDMI converter
> 
> On 09/30/2024, Biju Das wrote:
> > Hi Liu,
> 
> Hi Biju,
> 
> >
> >> -----Original Message-----
> >> From: Liu Ying <victor.liu@nxp.com>
> >> Sent: Monday, September 30, 2024 10:16 AM
> >> Subject: Re: [PATCH 5/8] dt-bindings: display: bridge: Add ITE IT6263
> >> LVDS to HDMI converter
> >>
> >> On 09/30/2024, Biju Das wrote:
> >>> Hi Liu,
> >>
> >> Hi Biju,
> >>
> >>>
> >>> thanks for the patch.
> >>>
> >>>> -----Original Message-----
> >>>> From: linux-arm-kernel
> >>>> <linux-arm-kernel-bounces@lists.infradead.org>
> >>>> On Behalf Of Liu Ying
> >>>> Sent: Monday, September 30, 2024 6:29 AM
> >>>> Subject: [PATCH 5/8] dt-bindings: display: bridge: Add ITE IT6263
> >>>> LVDS to HDMI converter
> >>>>
> >>>> Document ITE IT6263 LVDS to HDMI converter.
> >>>>
> >>>> Product link:
> >>>> https://www.ite.com.tw/en/product/cate1/IT6263
> >>>>
> >>>> Signed-off-by: Liu Ying <victor.liu@nxp.com>
> >>>> ---
> >>>>  .../bindings/display/bridge/ite,it6263.yaml   | 310 ++++++++++++++++++
> >>>>  1 file changed, 310 insertions(+)
> >>>>  create mode 100644
> >>>> Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml
> >>>>
> >>>> diff --git
> >>>> a/Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml
> >>>> b/Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml
> >>>> new file mode 100644
> >>>> index 000000000000..97fb81e5bc4a
> >>>> --- /dev/null
> >>>> +++ b/Documentation/devicetree/bindings/display/bridge/ite,it6263.y
> >>>> +++ am
> >>>> +++ l
> >>>> @@ -0,0 +1,310 @@
> >>>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML
> >>>> +1.2
> >>>> +---
> >>>> +$id: http://devicetree.org/schemas/display/bridge/ite,it6263.yaml#
> >>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> >>>> +
> >>>> +title: ITE IT6263 LVDS to HDMI converter
> >>>> +
> >>>> +maintainers:
> >>>> +  - Liu Ying <victor.liu@nxp.com>
> >>>> +
> >>>> +description: |
> >>>> +  The IT6263 is a high-performance single-chip De-SSC(De-Spread
> >>>> +Spectrum) LVDS
> >>>> +  to HDMI converter.  Combined with LVDS receiver and HDMI 1.4a
> >>>> +transmitter,
> >>>> +  the IT6263 supports LVDS input and HDMI 1.4 output by conversion function.
> >>>> +  The built-in LVDS receiver can support single-link and dual-link
> >>>> +LVDS inputs,
> >>>> +  and the built-in HDMI transmitter is fully compliant with HDMI
> >>>> +1.4a/3D, HDCP
> >>>> +  1.2 and backward compatible with DVI 1.0 specification.
> >>>> +
> >>>> +  The IT6263 also encodes and transmits up to 8 channels of I2S
> >>>> + digital audio,  with sampling rate up to 192KHz and sample size up to 24 bits.
> >>>> + In addition,  an S/PDIF input port takes in compressed audio of up to 192KHz frame rate.
> >>>> +
> >>>> +  The newly supported High-Bit Rate(HBR) audio by HDMI
> >>>> + specifications
> >>>> + v1.3 is  provided by the IT6263 in two interfaces: the four I2S
> >>>> + input ports or the  S/PDIF input port.  With both interfaces the
> >>>> + highest possible HBR frame rate  is supported at up to 768KHz.
> >>>> +
> >>>> +properties:
> >>>> +  compatible:
> >>>> +    const: ite,it6263
> >>>> +
> >>>> +  reg:
> >>>> +    maxItems: 1
> >>>> +
> >>>> +  clocks:
> >>>> +    maxItems: 1
> >>>> +    description: audio master clock
> >>>> +
> >>>> +  clock-names:
> >>>> +    const: mclk
> >>>> +
> >>>> +  reset-gpios:
> >>>> +    maxItems: 1
> >>>> +
> >>>> +  ivdd-supply:
> >>>> +    description: 1.8V digital logic power
> >>>> +
> >>>> +  ovdd-supply:
> >>>> +    description: 3.3V I/O pin power
> >>>> +
> >>>> +  txavcc18-supply:
> >>>> +    description: 1.8V HDMI analog frontend power
> >>>> +
> >>>> +  txavcc33-supply:
> >>>> +    description: 3.3V HDMI analog frontend power
> >>>> +
> >>>> +  pvcc1-supply:
> >>>> +    description: 1.8V HDMI frontend core PLL power
> >>>> +
> >>>> +  pvcc2-supply:
> >>>> +    description: 1.8V HDMI frontend filter PLL power
> >>>> +
> >>>> +  avcc-supply:
> >>>> +    description: 3.3V LVDS frontend power
> >>>> +
> >>>> +  anvdd-supply:
> >>>> +    description: 1.8V LVDS frontend analog power
> >>>> +
> >>>> +  apvdd-supply:
> >>>> +    description: 1.8V LVDS frontend PLL power
> >>>> +
> >>>> +  "#sound-dai-cells":
> >>>> +    const: 0
> >>>> +
> >>>> +  ite,i2s-audio-fifo-sources:
> >>>> +    $ref: /schemas/types.yaml#/definitions/uint32-array
> >>>> +    minItems: 1
> >>>> +    maxItems: 4
> >>>> +    items:
> >>>> +      enum: [0, 1, 2, 3]
> >>>> +    description:
> >>>> +      Each array element indicates the pin number of an I2S serial data input
> >>>> +      line which is connected to an audio FIFO, from audio FIFO0 to FIFO3.
> >>>> +
> >>>> +  ite,rl-channel-swap-audio-sources:
> >>>> +    $ref: /schemas/types.yaml#/definitions/uint32-array
> >>>> +    minItems: 1
> >>>> +    maxItems: 4
> >>>> +    uniqueItems: true
> >>>> +    items:
> >>>> +      enum: [0, 1, 2, 3]
> >>>> +    description:
> >>>> +      Each array element indicates an audio source whose right channel and left
> >>>> +      channel are swapped by this converter. For I2S, the element is the pin
> >>>> +      number of an I2S serial data input line. For S/PDIF, the element is always
> >>>> +      0.
> >>>> +
> >>>> +  ports:
> >>>> +    $ref: /schemas/graph.yaml#/properties/ports
> >>>> +
> >>>> +    oneOf:
> >>>> +      - properties:
> >>>> +          port@0:
> >>>> +            $ref: /schemas/graph.yaml#/properties/port
> >>>> +            description: the first LVDS input link
> >>>> +
> >>>> +          port@1: false
> >>>> +
> >>>> +          port@2:
> >>>> +            $ref: /schemas/graph.yaml#/properties/port
> >>>> +            description: video port for the HDMI output
> >>>> +
> >>>> +          port@3:
> >>>> +            $ref: /schemas/graph.yaml#/properties/port
> >>>> +            description: sound input port
> >>>> +
> >>>> +        required:
> >>>> +          - port@0
> >>>> +          - port@2
> >>>> +
> >>>> +      - properties:
> >>>> +          port@0:
> >>>> +            $ref: /schemas/graph.yaml#/$defs/port-base
> >>>> +            unevaluatedProperties: false
> >>>> +            description: the first LVDS input link
> >>>> +
> >>>> +            properties:
> >>>> +              dual-lvds-odd-pixels:
> >>>> +                type: boolean
> >>>> +                description: the first sink port for odd pixels
> >>>> +
> >>>> +              dual-lvds-even-pixels:
> >>>> +                type: boolean
> >>>> +                description: the first sink port for even pixels
> >>>> +
> >>>> +            oneOf:
> >>>> +              - required: [dual-lvds-odd-pixels]
> >>>> +              - required: [dual-lvds-even-pixels]
> >>>> +
> >>>> +          port@1:
> >>>> +            $ref: /schemas/graph.yaml#/$defs/port-base
> >>>> +            unevaluatedProperties: false
> >>>> +            description: the second LVDS input link
> >>>> +
> >>>> +            properties:
> >>>> +              dual-lvds-even-pixels:
> >>>> +                type: boolean
> >>>> +                description: the second sink port for even pixels
> >>>> +
> >>>> +              dual-lvds-odd-pixels:
> >>>> +                type: boolean
> >>>> +                description: the second sink port for odd pixels
> >>>> +
> >>>> +            oneOf:
> >>>> +              - required: [dual-lvds-even-pixels]
> >>>> +              - required: [dual-lvds-odd-pixels]
> >>>
> >>>
> >>>> +
> >>>> +          port@2:
> >>>> +            $ref: /schemas/graph.yaml#/properties/port
> >>>> +            description: video port for the HDMI output
> >>>> +
> >>>> +          port@3:
> >>>> +            $ref: /schemas/graph.yaml#/properties/port
> >>>> +            description: sound input port
> >>>
> >>> What about single lvds as device support it?
> >>
> >> The single LVDS link has already been documented in this binding doc.
> >> Please find the "properties" above where only "port@0" and "port@2"
> >> are required.
> >
> > Maybe "the first LVDS input link"-->"Single LVDS input link" for single LVDS block??
> 
> Nope.
> 
> I tested single LVDS link with the second LVDS link.  It didn't work.
> The single LVDS link only works with the first LVDS link.

OK. That is the reason you made port@1 false.

Still port@0 is a single LVDS instance or first LVDS input link for the dual
LVDS configuration??

Cheers,
Biju


> 
> >
> >>
> >> imx8mp-evk-lvds0-imx-lvds-hdmi.dtso and
> >> imx8mp-evk-lvds1-imx-lvds-hdmi.dtso
> >> added in patch 7 support the NXP adapter card with single LVDS link.
> >>
> >>>
> >>> Cheers,
> >>> Biju
> >>>
> >>>> +
> >>>> +        required:
> >>>> +          - port@0
> >>>> +          - port@1
> >>>> +          - port@2
> >>>> +
> >>>> +        allOf:
> >>>> +          - if:
> >>>> +              properties:
> >>>> +                port@0:
> >>>> +                  required:
> >>>> +                    - dual-lvds-odd-pixels
> >>>> +            then:
> >>>> +              properties:
> >>>> +                port@1:
> >>>> +                  properties:
> >>>> +                    dual-lvds-odd-pixels: false
> >>>> +
> >>>> +          - if:
> >>>> +              properties:
> >>>> +                port@0:
> >>>> +                  required:
> >>>> +                    - dual-lvds-even-pixels
> >>>> +            then:
> >>>> +              properties:
> >>>> +                port@1:
> >>>> +                  properties:
> >>>> +                    dual-lvds-even-pixels: false
> >>>> +
> >>>> +required:
> >>>> +  - compatible
> >>>> +  - reg
> >>>> +  - ivdd-supply
> >>>> +  - ovdd-supply
> >>>> +  - txavcc18-supply
> >>>> +  - txavcc33-supply
> >>>> +  - pvcc1-supply
> >>>> +  - pvcc2-supply
> >>>> +  - avcc-supply
> >>>> +  - anvdd-supply
> >>>> +  - apvdd-supply
> >>>> +  - ports
> >>>> +
> >>>> +additionalProperties: false
> >>>> +
> >>>> +examples:
> >>>> +  - |
> >>>> +    /* single-link LVDS input */
> >>>> +    #include <dt-bindings/gpio/gpio.h>
> >>>> +
> >>>> +    i2c {
> >>>> +        #address-cells = <1>;
> >>>> +        #size-cells = <0>;
> >>>> +
> >>>> +        hdmi@4c {
> >>>> +            compatible = "ite,it6263";
> >>>> +            reg = <0x4c>;
> >>>> +            reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
> >>>> +            ivdd-supply = <&reg_buck5>;
> >>>> +            ovdd-supply = <&reg_vext_3v3>;
> >>>> +            txavcc18-supply = <&reg_buck5>;
> >>>> +            txavcc33-supply = <&reg_vext_3v3>;
> >>>> +            pvcc1-supply = <&reg_buck5>;
> >>>> +            pvcc2-supply = <&reg_buck5>;
> >>>> +            avcc-supply = <&reg_vext_3v3>;
> >>>> +            anvdd-supply = <&reg_buck5>;
> >>>> +            apvdd-supply = <&reg_buck5>;
> >>>> +
> >>>> +            ports {
> >>>> +                #address-cells = <1>;
> >>>> +                #size-cells = <0>;
> >>>> +
> >>>> +                port@0 {
> >>>> +                    reg = <0>;
> >>>> +
> >>>> +                    it6263_lvds_link1: endpoint {
> >>>> +                        remote-endpoint = <&ldb_lvds_ch0>;
> >>>> +                    };
> >>>> +                };
> >>>> +
> >>>> +                port@2 {
> >>>> +                    reg = <2>;
> >>>> +
> >>>> +                    it6263_out: endpoint {
> >>>> +                        remote-endpoint = <&hdmi_in>;
> >>>> +                    };
> >>>> +                };
> >>>> +            };
> >>>> +        };
> >>>> +    };
> >>>> +
> >>>> +  - |
> >>>> +    /* dual-link LVDS input */
> >>>> +    #include <dt-bindings/gpio/gpio.h>
> >>>> +
> >>>> +    i2c {
> >>>> +        #address-cells = <1>;
> >>>> +        #size-cells = <0>;
> >>>> +
> >>>> +        hdmi@4c {
> >>>> +            compatible = "ite,it6263";
> >>>> +            reg = <0x4c>;
> >>>> +            reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
> >>>> +            ivdd-supply = <&reg_buck5>;
> >>>> +            ovdd-supply = <&reg_vext_3v3>;
> >>>> +            txavcc18-supply = <&reg_buck5>;
> >>>> +            txavcc33-supply = <&reg_vext_3v3>;
> >>>> +            pvcc1-supply = <&reg_buck5>;
> >>>> +            pvcc2-supply = <&reg_buck5>;
> >>>> +            avcc-supply = <&reg_vext_3v3>;
> >>>> +            anvdd-supply = <&reg_buck5>;
> >>>> +            apvdd-supply = <&reg_buck5>;
> >>>> +
> >>>> +            ports {
> >>>> +                #address-cells = <1>;
> >>>> +                #size-cells = <0>;
> >>>> +
> >>>> +                port@0 {
> >>>> +                    reg = <0>;
> >>>> +                    dual-lvds-odd-pixels;
> >>>> +
> >>>> +                    it6263_lvds_link1_dual: endpoint {
> >>>> +                        remote-endpoint = <&ldb_lvds_ch0>;
> >>>> +                    };
> >>>> +                };
> >>>> +
> >>>> +                port@1 {
> >>>> +                    reg = <1>;
> >>>> +                    dual-lvds-even-pixels;
> >>>> +
> >>>> +                    it6263_lvds_link2_dual: endpoint {
> >>>> +                        remote-endpoint = <&ldb_lvds_ch1>;
> >>>> +                    };
> >>>> +                };
> >>>> +
> >>>> +                port@2 {
> >>>> +                    reg = <2>;
> >>>> +
> >>>> +                    it6263_out_dual: endpoint {
> >>>> +                        remote-endpoint = <&hdmi_in>;
> >>>> +                    };
> >>>> +                };
> >>>> +            };
> >>>> +        };
> >>>> +    };
> >>>> --
> >>>> 2.34.1
> >>>>
> >>>
> >>
> >> --
> >> Regards,
> >> Liu Ying
> >
> 
> --
> Regards,
> Liu Ying


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

* Re: [PATCH 6/8] drm/bridge: Add ITE IT6263 LVDS to HDMI converter
  2024-09-30  9:16   ` Biju Das
@ 2024-09-30  9:40     ` Liu Ying
  2024-09-30  9:45       ` Biju Das
  2024-09-30 13:10     ` Biju Das
  1 sibling, 1 reply; 38+ messages in thread
From: Liu Ying @ 2024-09-30  9:40 UTC (permalink / raw)
  To: Biju Das, dri-devel@lists.freedesktop.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linux-arm-kernel@lists.infradead.org
  Cc: andrzej.hajda@intel.com, neil.armstrong@linaro.org,
	rfoss@kernel.org, laurent.pinchart, jonas@kwiboo.se,
	jernej.skrabec@gmail.com, maarten.lankhorst@linux.intel.com,
	mripard@kernel.org, tzimmermann@suse.de, airlied@gmail.com,
	simona@ffwll.ch, robh@kernel.org, krzk+dt@kernel.org,
	conor+dt@kernel.org, shawnguo@kernel.org, s.hauer@pengutronix.de,
	kernel@pengutronix.de, festevam@gmail.com,
	catalin.marinas@arm.com, will@kernel.org,
	quic_bjorande@quicinc.com, geert+renesas@glider.be,
	dmitry.baryshkov@linaro.org, arnd@arndb.de,
	nfraprado@collabora.com, o.rempel@pengutronix.de,
	y.moog@phytec.de

On 09/30/2024, Biju Das wrote:
> Hi Liu,

Hi Biju,

> 
> Thanks for the patch.
> 
>> -----Original Message-----
>> From: linux-arm-kernel <linux-arm-kernel-bounces@lists.infradead.org> On Behalf Of Liu Ying
>> Sent: Monday, September 30, 2024 6:29 AM
>> Subject: [PATCH 6/8] drm/bridge: Add ITE IT6263 LVDS to HDMI converter
>>
>> Add basic HDMI video output support. Currently, only RGB888 output pixel format is supported.  At the
>> LVDS input side, the driver supports single LVDS link and dual LVDS links with "jeida-24" LVDS
>> mapping.
>>
>> Product link:
>> https://www.ite.com.tw/en/product/cate1/IT6263
>>
>> Signed-off-by: Liu Ying <victor.liu@nxp.com>
>> ---
>>  drivers/gpu/drm/bridge/Kconfig      |   8 +
>>  drivers/gpu/drm/bridge/Makefile     |   1 +
>>  drivers/gpu/drm/bridge/ite-it6263.c | 829 ++++++++++++++++++++++++++++
>>  3 files changed, 838 insertions(+)
>>  create mode 100644 drivers/gpu/drm/bridge/ite-it6263.c
>>
>> diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index
>> 3eb955333c80..93f99682a090 100644
>> --- a/drivers/gpu/drm/bridge/Kconfig
>> +++ b/drivers/gpu/drm/bridge/Kconfig
>> @@ -90,6 +90,14 @@ config DRM_FSL_LDB
>>  	help
>>  	  Support for i.MX8MP DPI-to-LVDS on-SoC encoder.
>>
>> +config DRM_ITE_IT6263
>> +	tristate "ITE IT6263 LVDS/HDMI bridge"
>> +	depends on OF
>> +	select DRM_KMS_HELPER
>> +	select REGMAP_I2C
>> +	help
>> +	  ITE IT6263 LVDS to HDMI bridge chip driver.
>> +
>>  config DRM_ITE_IT6505
>>  	tristate "ITE IT6505 DisplayPort bridge"
>>  	depends on OF
>> diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index
>> 7df87b582dca..f3776dd473fd 100644
>> --- a/drivers/gpu/drm/bridge/Makefile
>> +++ b/drivers/gpu/drm/bridge/Makefile
>> @@ -6,6 +6,7 @@ obj-$(CONFIG_DRM_CHRONTEL_CH7033) += chrontel-ch7033.o
>>  obj-$(CONFIG_DRM_CROS_EC_ANX7688) += cros-ec-anx7688.o
>>  obj-$(CONFIG_DRM_DISPLAY_CONNECTOR) += display-connector.o
>>  obj-$(CONFIG_DRM_FSL_LDB) += fsl-ldb.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
>>  obj-$(CONFIG_DRM_LONTIUM_LT9211) += lontium-lt9211.o diff --git a/drivers/gpu/drm/bridge/ite-it6263.c
>> b/drivers/gpu/drm/bridge/ite-it6263.c
>> new file mode 100644
>> index 000000000000..886588497bc1
>> --- /dev/null
>> +++ b/drivers/gpu/drm/bridge/ite-it6263.c
>> @@ -0,0 +1,829 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Copyright 2024 NXP
>> + */
>> +
>> +#include <linux/bitfield.h>
>> +#include <linux/bits.h>
>> +#include <linux/delay.h>
>> +#include <linux/gpio/consumer.h>
>> +#include <linux/i2c.h>
>> +#include <linux/media-bus-format.h>
>> +#include <linux/module.h>
>> +#include <linux/of.h>
>> +#include <linux/regmap.h>
>> +#include <linux/regulator/consumer.h>
>> +
>> +#include <drm/drm_atomic.h>
>> +#include <drm/drm_atomic_helper.h>
>> +#include <drm/drm_atomic_state_helper.h> #include <drm/drm_bridge.h>
>> +#include <drm/drm_connector.h> #include <drm/drm_crtc.h> #include
>> +<drm/drm_edid.h> #include <drm/drm_of.h> #include
>> +<drm/drm_probe_helper.h>
>> +
>> +/*
>> +-----------------------------------------------------------------------
>> +------
>> + * LVDS registers
>> + */
>> +
>> +/* LVDS software reset registers */
>> +#define LVDS_REG_05			0x05
>> +#define  REG_SOFT_P_RST			BIT(1)
>> +
>> +/* LVDS system configuration registers */
>> +/* 0x0b */
>> +#define LVDS_REG_0B			0x0b
>> +#define  REG_SSC_PCLK_RF		BIT(0)
>> +#define  REG_LVDS_IN_SWAP		BIT(1)
>> +
>> +/* LVDS test pattern gen control registers */
>> +/* 0x2c */
>> +#define LVDS_REG_2C			0x2c
>> +#define  REG_COL_DEP			GENMASK(1, 0)
>> +#define  BIT8				FIELD_PREP(REG_COL_DEP, 2)
>> +#define  OUT_MAP			BIT(4)
>> +#define  JEIDA				0
>> +#define  REG_DESSC_ENB			BIT(6)
>> +#define  DMODE				BIT(7)
>> +#define  DISO				BIT(7)
>> +#define  SISO				0
>> +
>> +#define LVDS_REG_3C			0x3c
>> +#define LVDS_REG_3F			0x3f
>> +#define LVDS_REG_47			0x47
>> +#define LVDS_REG_48			0x48
>> +#define LVDS_REG_4F			0x4f
>> +#define LVDS_REG_52			0x52
>> +
>> +/*
>> +-----------------------------------------------------------------------
>> +------
>> + * HDMI registers are separated into three banks:
>> + * 1) HDMI register common bank: 0x00 ~ 0x2f  */
>> +
>> +/* HDMI genernal registers */
>> +#define HDMI_REG_SW_RST			0x04
>> +#define  SOFTREF_RST			BIT(5)
>> +#define  SOFTA_RST			BIT(4)
>> +#define  SOFTV_RST			BIT(3)
>> +#define  AUD_RST			BIT(2)
>> +#define  HDCP_RST			BIT(0)
>> +#define  HDMI_RST_ALL			(SOFTREF_RST | SOFTA_RST | SOFTV_RST | \
>> +					 AUD_RST | HDCP_RST)
>> +
>> +#define HDMI_REG_SYS_STATUS		0x0e
>> +#define  HPDETECT			BIT(6)
>> +#define  TXVIDSTABLE			BIT(4)
>> +
>> +#define HDMI_REG_BANK_CTRL		0x0f
>> +#define  REG_BANK_SEL			BIT(0)
>> +
>> +/* HDMI System DDC control registers */
>> +#define HDMI_REG_DDC_MASTER_CTRL	0x10
>> +#define  MASTER_SEL_HOST		BIT(0)
>> +
>> +#define HDMI_REG_DDC_HEADER		0x11
>> +
>> +#define HDMI_REG_DDC_REQOFF		0x12
>> +#define HDMI_REG_DDC_REQCOUNT		0x13
>> +#define HDMI_REG_DDC_EDIDSEG		0x14
>> +
>> +#define HDMI_REG_DDC_CMD		0x15
>> +#define  DDC_CMD_EDID_READ		0x3
>> +#define  DDC_CMD_FIFO_CLR		0x9
>> +
>> +#define HDMI_REG_DDC_STATUS		0x16
>> +#define  DDC_DONE			BIT(7)
>> +#define  DDC_NOACK			BIT(5)
>> +#define  DDC_WAITBUS			BIT(4)
>> +#define  DDC_ARBILOSE			BIT(3)
>> +#define  DDC_ERROR			(DDC_NOACK | DDC_WAITBUS | DDC_ARBILOSE)
>> +
>> +#define HDMI_DDC_FIFO_BYTES		32
>> +#define HDMI_REG_DDC_READFIFO		0x17
>> +#define HDMI_REG_LVDS_PORT		0x1d /* LVDS input control I2C addr */
>> +#define HDMI_REG_LVDS_PORT_EN		0x1e
>> +#define LVDS_INPUT_CTRL_I2C_ADDR	0x33
>> +
>> +/*
>> +-----------------------------------------------------------------------
>> +------
>> + * 2) HDMI register bank0: 0x30 ~ 0xff
>> + */
>> +
>> +/* HDMI AFE registers */
>> +#define HDMI_REG_AFE_DRV_CTRL		0x61
>> +#define  AFE_DRV_PWD			BIT(5)
>> +#define  AFE_DRV_RST			BIT(4)
>> +
>> +#define HDMI_REG_AFE_XP_CTRL		0x62
>> +#define  AFE_XP_GAINBIT			BIT(7)
>> +#define  AFE_XP_ER0			BIT(4)
>> +#define  AFE_XP_RESETB			BIT(3)
>> +
>> +#define HDMI_REG_AFE_ISW_CTRL		0x63
>> +
>> +#define HDMI_REG_AFE_IP_CTRL		0x64
>> +#define  AFE_IP_GAINBIT			BIT(7)
>> +#define  AFE_IP_ER0			BIT(3)
>> +#define  AFE_IP_RESETB			BIT(2)
>> +
>> +/* HDMI input data format registers */
>> +#define HDMI_REG_INPUT_MODE		0x70
>> +#define  IN_RGB				0x00
>> +
>> +/* HDMI general control registers */
>> +#define HDMI_REG_HDMI_MODE		0xc0
>> +#define  TX_HDMI_MODE			BIT(0)
>> +
>> +#define HDMI_REG_GCP			0xc1
>> +#define  AVMUTE				BIT(0)
>> +#define  HDMI_COLOR_DEPTH		GENMASK(6, 4)
>> +#define  HDMI_COLOR_DEPTH_24		FIELD_PREP(HDMI_COLOR_DEPTH, 4)
>> +
>> +#define HDMI_REG_PKT_GENERAL_CTRL	0xc6
>> +#define  ENABLE_PKT			BIT(0)
>> +#define  REPEAT_PKT			BIT(1)
>> +
>> +/*
>> +-----------------------------------------------------------------------
>> +------
>> + * 3) HDMI register bank1: 0x130 ~ 0x1ff (HDMI packet registers)  */
>> +
>> +/* AVI packet registers */
>> +#define HDMI_REG_AVI_DB1		0x158
>> +#define  AVI_DB1_COLOR_SPACE		GENMASK(6, 5)
>> +#define  AVI_COLOR_SPACE_RGB		FIELD_PREP(AVI_DB1_COLOR_SPACE, 0)
>> +
>> +#define MAX_PIXEL_CLOCK_KHZ		150000
>> +#define HIGH_PIXEL_CLOCK_KHZ		80000
>> +
>> +struct it6263 {
>> +	struct device *dev;
>> +	struct i2c_client *hdmi_i2c;
>> +	struct i2c_client *lvds_i2c;
>> +	struct regmap *hdmi_regmap;
>> +	struct regmap *lvds_regmap;
>> +	struct drm_bridge bridge;
>> +	struct drm_bridge *next_bridge;
>> +	struct drm_connector connector;
>> +	struct gpio_desc *reset_gpio;
>> +	bool lvds_dual_link;
>> +	bool lvds_link12_swap;
>> +};
>> +
>> +static inline struct it6263 *bridge_to_it6263(struct drm_bridge
>> +*bridge) {
>> +	return container_of(bridge, struct it6263, bridge); }
>> +
>> +static inline struct it6263 *connector_to_it6263(struct drm_connector
>> +*conn) {
>> +	return container_of(conn, struct it6263, connector); }
>> +
>> +static bool it6263_hdmi_writeable_reg(struct device *dev, unsigned int
>> +reg) {
>> +	switch (reg) {
>> +	case HDMI_REG_SW_RST:
>> +	case HDMI_REG_BANK_CTRL:
>> +	case HDMI_REG_DDC_MASTER_CTRL:
>> +	case HDMI_REG_DDC_HEADER:
>> +	case HDMI_REG_DDC_REQOFF:
>> +	case HDMI_REG_DDC_REQCOUNT:
>> +	case HDMI_REG_DDC_EDIDSEG:
>> +	case HDMI_REG_DDC_CMD:
>> +	case HDMI_REG_LVDS_PORT:
>> +	case HDMI_REG_LVDS_PORT_EN:
>> +	case HDMI_REG_AFE_DRV_CTRL:
>> +	case HDMI_REG_AFE_XP_CTRL:
>> +	case HDMI_REG_AFE_ISW_CTRL:
>> +	case HDMI_REG_AFE_IP_CTRL:
>> +	case HDMI_REG_INPUT_MODE:
>> +	case HDMI_REG_HDMI_MODE:
>> +	case HDMI_REG_GCP:
>> +	case HDMI_REG_PKT_GENERAL_CTRL:
>> +	case HDMI_REG_AVI_DB1:
>> +		return true;
>> +	default:
>> +		return false;
>> +	}
>> +}
>> +
>> +static bool it6263_hdmi_readable_reg(struct device *dev, unsigned int
>> +reg) {
>> +	if (it6263_hdmi_writeable_reg(dev, reg))
>> +		return true;
>> +
>> +	switch (reg) {
>> +	case HDMI_REG_SYS_STATUS:
>> +	case HDMI_REG_DDC_STATUS:
>> +	case HDMI_REG_DDC_READFIFO:
>> +		return true;
>> +	default:
>> +		return false;
>> +	}
>> +}
>> +
>> +static bool it6263_hdmi_volatile_reg(struct device *dev, unsigned int
>> +reg) {
>> +	switch (reg) {
>> +	case HDMI_REG_SW_RST:
>> +	case HDMI_REG_SYS_STATUS:
>> +	case HDMI_REG_DDC_STATUS:
>> +	case HDMI_REG_DDC_READFIFO:
>> +		return true;
>> +	default:
>> +		return false;
>> +	}
>> +}
>> +
>> +static const struct regmap_range_cfg it6263_hdmi_range_cfg = {
>> +	.range_min = 0x00,
>> +	.range_max = HDMI_REG_AVI_DB1,
>> +	.selector_reg = HDMI_REG_BANK_CTRL,
>> +	.selector_mask = REG_BANK_SEL,
>> +	.selector_shift = 0,
>> +	.window_start = 0x00,
>> +	.window_len = 0x100,
>> +};
>> +
>> +static const struct regmap_config it6263_hdmi_regmap_config = {
>> +	.name = "it6263-hdmi",
>> +	.reg_bits = 8,
>> +	.val_bits = 8,
>> +	.writeable_reg = it6263_hdmi_writeable_reg,
>> +	.readable_reg = it6263_hdmi_readable_reg,
>> +	.volatile_reg = it6263_hdmi_volatile_reg,
>> +	.max_register = HDMI_REG_AVI_DB1,
>> +	.ranges = &it6263_hdmi_range_cfg,
>> +	.num_ranges = 1,
>> +	.cache_type = REGCACHE_MAPLE,
>> +};
>> +
>> +static bool it6263_lvds_writeable_reg(struct device *dev, unsigned int
>> +reg) {
>> +	switch (reg) {
>> +	case LVDS_REG_05:
>> +	case LVDS_REG_0B:
>> +	case LVDS_REG_2C:
>> +	case LVDS_REG_3C:
>> +	case LVDS_REG_3F:
>> +	case LVDS_REG_47:
>> +	case LVDS_REG_48:
>> +	case LVDS_REG_4F:
>> +	case LVDS_REG_52:
>> +		return true;
>> +	default:
>> +		return false;
>> +	}
>> +}
>> +
>> +static bool it6263_lvds_readable_reg(struct device *dev, unsigned int
>> +reg) {
>> +	return it6263_lvds_writeable_reg(dev, reg); }
>> +
>> +static bool it6263_lvds_volatile_reg(struct device *dev, unsigned int
>> +reg) {
>> +	return reg == LVDS_REG_05;
>> +}
>> +
>> +static const struct regmap_config it6263_lvds_regmap_config = {
>> +	.name = "it6263-lvds",
>> +	.reg_bits = 8,
>> +	.val_bits = 8,
>> +	.writeable_reg = it6263_lvds_writeable_reg,
>> +	.readable_reg = it6263_lvds_readable_reg,
>> +	.volatile_reg = it6263_lvds_volatile_reg,
>> +	.max_register = LVDS_REG_52,
>> +	.cache_type = REGCACHE_MAPLE,
>> +};
>> +
>> +static const char * const it6263_supplies[] = {
>> +	"ivdd", "ovdd", "txavcc18", "txavcc33", "pvcc1", "pvcc2",
>> +	"avcc", "anvdd", "apvdd"
>> +};
>> +
>> +static int it6263_parse_dt(struct it6263 *it) {
>> +	struct device *dev = it->dev;
>> +	struct device_node *port0, *port1;
>> +	int ret = 0;
>> +
>> +	it->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 2, 0);
>> +	if (IS_ERR(it->next_bridge))
>> +		return dev_err_probe(dev, PTR_ERR(it->next_bridge),
>> +				     "failed to get next bridge\n");
>> +
>> +	port0 = of_graph_get_port_by_id(dev->of_node, 0);
>> +	port1 = of_graph_get_port_by_id(dev->of_node, 1);
>> +	if (port0 && port1) {
>> +		if (of_property_read_bool(port0, "dual-lvds-even-pixels") &&
>> +		    of_property_read_bool(port1, "dual-lvds-odd-pixels")) {
>> +			it->lvds_dual_link = true;
>> +			it->lvds_link12_swap = true;
>> +		} else if (of_property_read_bool(port0, "dual-lvds-odd-pixels") &&
>> +			   of_property_read_bool(port1, "dual-lvds-even-pixels")) {
>> +			it->lvds_dual_link = true;
>> +		}
>> +
>> +		if (!it->lvds_dual_link) {
>> +			dev_err(dev,
>> +				"failed to get LVDS dual link pixel order\n");
>> +			ret = -EINVAL;
>> +		}
>> +	} else if (port1) {
>> +		ret = -EINVAL;
>> +		dev_err(dev, "single input LVDS port1 is not supported\n");
> 
> 		Are you supporting single input LVDS port0??
> 
>> +	} else if (!port0) {
>> +		ret = -EINVAL;
>> +		dev_err(dev, "no input LVDS port\n");
>> +	}
>> +
>> +	of_node_put(port0);
>> +	of_node_put(port1);
>> +
>> +	return ret;
>> +}
>> +
>> +static inline void it6263_reset(struct it6263 *it) {
>> +	if (!it->reset_gpio)
>> +		return;
>> +
>> +	gpiod_set_value_cansleep(it->reset_gpio, 0);
>> +	fsleep(1000);
>> +	gpiod_set_value_cansleep(it->reset_gpio, 1);
>> +	/* The chip maker says the low pulse should be at least 40ms. */
>> +	fsleep(40000);
>> +	gpiod_set_value_cansleep(it->reset_gpio, 0);
>> +	/* addtional time to wait the high voltage to be stable */
>> +	fsleep(5000);
> 
> What about other resets ??
> 
> /* AFE PLL reset and  pclk reset */
> 
>> +}
>> +
>> +static inline int it6263_lvds_set_i2c_addr(struct it6263 *it) {
>> +	int ret;
>> +
>> +	ret = regmap_write(it->hdmi_regmap, HDMI_REG_LVDS_PORT,
>> +			   LVDS_INPUT_CTRL_I2C_ADDR << 1);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return regmap_write(it->hdmi_regmap, HDMI_REG_LVDS_PORT_EN, BIT(0)); }
>> +
>> +static inline void it6263_lvds_reset(struct it6263 *it) {
>> +	/* AFE PLL reset */
>> +	regmap_write_bits(it->lvds_regmap, LVDS_REG_3C, BIT(0), 0x0);
>> +	fsleep(1000);
>> +	regmap_write_bits(it->lvds_regmap, LVDS_REG_3C, BIT(0), BIT(0));
>> +
>> +	/* software pixel clock domain reset */
>> +	regmap_write_bits(it->lvds_regmap, LVDS_REG_05, REG_SOFT_P_RST,
>> +			  REG_SOFT_P_RST);
>> +	fsleep(1000);
>> +	regmap_write_bits(it->lvds_regmap, LVDS_REG_05, REG_SOFT_P_RST, 0x0);
>> +	fsleep(10000);
>> +}
>> +
>> +static inline void it6263_lvds_set_interface(struct it6263 *it) {
>> +	/* color depth */
>> +	regmap_write_bits(it->lvds_regmap, LVDS_REG_2C, REG_COL_DEP, BIT8);
>> +	/* output mapping */
>> +	regmap_write_bits(it->lvds_regmap, LVDS_REG_2C, OUT_MAP, JEIDA);
>> +
>> +	if (it->lvds_dual_link) {
>> +		regmap_write_bits(it->lvds_regmap, LVDS_REG_2C, DMODE, DISO);
>> +		regmap_write_bits(it->lvds_regmap, LVDS_REG_52, BIT(1), BIT(1));
>> +	} else {
>> +		regmap_write_bits(it->lvds_regmap, LVDS_REG_2C, DMODE, SISO);
>> +		regmap_write_bits(it->lvds_regmap, LVDS_REG_52, BIT(1), 0);
>> +	}
>> +}
>> +
>> +static inline void it6263_lvds_set_afe(struct it6263 *it) {
>> +	regmap_write(it->lvds_regmap, LVDS_REG_3C, 0xaa);
>> +	regmap_write(it->lvds_regmap, LVDS_REG_3F, 0x02);
>> +	regmap_write(it->lvds_regmap, LVDS_REG_47, 0xaa);
>> +	regmap_write(it->lvds_regmap, LVDS_REG_48, 0x02);
>> +	regmap_write(it->lvds_regmap, LVDS_REG_4F, 0x11);
>> +
>> +	regmap_write_bits(it->lvds_regmap, LVDS_REG_0B, REG_SSC_PCLK_RF,
>> +			  REG_SSC_PCLK_RF);
>> +	regmap_write_bits(it->lvds_regmap, LVDS_REG_3C, 0x07, 0);
>> +	regmap_write_bits(it->lvds_regmap, LVDS_REG_2C, REG_DESSC_ENB,
>> +			  REG_DESSC_ENB);
>> +}
>> +
>> +static inline void it6263_lvds_sys_cfg(struct it6263 *it) {
>> +	regmap_write_bits(it->lvds_regmap, LVDS_REG_0B, REG_LVDS_IN_SWAP,
>> +			  it->lvds_link12_swap ? REG_LVDS_IN_SWAP : 0); }
>> +
>> +static inline void it6263_lvds_config(struct it6263 *it) {
>> +	it6263_lvds_reset(it);
>> +	it6263_lvds_set_interface(it);
>> +	it6263_lvds_set_afe(it);
>> +	it6263_lvds_sys_cfg(it);
>> +}
>> +
>> +static inline void it6263_hdmi_config(struct it6263 *it) {
>> +	regmap_write(it->hdmi_regmap, HDMI_REG_SW_RST, HDMI_RST_ALL);
>> +	regmap_write(it->hdmi_regmap, HDMI_REG_INPUT_MODE, IN_RGB);
>> +	regmap_write_bits(it->hdmi_regmap, HDMI_REG_GCP, HDMI_COLOR_DEPTH,
>> +			  HDMI_COLOR_DEPTH_24);
>> +	regmap_write_bits(it->hdmi_regmap, HDMI_REG_AVI_DB1,
>> +			  AVI_DB1_COLOR_SPACE, AVI_COLOR_SPACE_RGB); }
>> +
>> +static enum drm_connector_status it6263_detect(struct it6263 *it) {
>> +	unsigned int val;
>> +
>> +	regmap_read(it->hdmi_regmap, HDMI_REG_SYS_STATUS, &val);
>> +	if (val & HPDETECT)
>> +		return connector_status_connected;
>> +	else
>> +		return connector_status_disconnected; }
>> +
>> +static enum drm_connector_status
>> +it6263_connector_detect(struct drm_connector *connector, bool force) {
>> +	struct it6263 *it = connector_to_it6263(connector);
>> +
>> +	return it6263_detect(it);
>> +}
>> +
>> +static const struct drm_connector_funcs it6263_connector_funcs = {
>> +	.detect = it6263_connector_detect,
>> +	.fill_modes = drm_helper_probe_single_connector_modes,
>> +	.destroy = drm_connector_cleanup,
>> +	.reset = drm_atomic_helper_connector_reset,
>> +	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
>> +	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
>> +};
>> +
>> +static int it6263_read_edid(void *data, u8 *buf, unsigned int block,
>> +size_t len) {
>> +	struct it6263 *it = data;
>> +	struct regmap *regmap = it->hdmi_regmap;
>> +	unsigned int start = (block % 2) * EDID_LENGTH;
>> +	unsigned int segment = block >> 1;
>> +	unsigned int count, val;
>> +	int ret;
>> +
>> +	regmap_write(regmap, HDMI_REG_DDC_MASTER_CTRL, MASTER_SEL_HOST);
>> +	regmap_write(regmap, HDMI_REG_DDC_HEADER, DDC_ADDR << 1);
>> +	regmap_write(regmap, HDMI_REG_DDC_EDIDSEG, segment);
>> +
>> +	while (len) {
>> +		/* clear DDC FIFO */
>> +		regmap_write(regmap, HDMI_REG_DDC_CMD, DDC_CMD_FIFO_CLR);
>> +
>> +		ret = regmap_read_poll_timeout(regmap, HDMI_REG_DDC_STATUS,
>> +					       val, val & DDC_DONE,
>> +					       2000, 10000);
>> +		if (ret) {
>> +			dev_err(it->dev, "failed to clear DDC FIFO:%d\n", ret);
>> +			return ret;
>> +		}
>> +
>> +		count = len > HDMI_DDC_FIFO_BYTES ? HDMI_DDC_FIFO_BYTES : len;
>> +
>> +		/* fire the read command */
>> +		regmap_write(regmap, HDMI_REG_DDC_REQOFF, start);
>> +		regmap_write(regmap, HDMI_REG_DDC_REQCOUNT, count);
>> +		regmap_write(regmap, HDMI_REG_DDC_CMD, DDC_CMD_EDID_READ);
>> +
>> +		start += count;
>> +		len -= count;
>> +
>> +		ret = regmap_read_poll_timeout(regmap, HDMI_REG_DDC_STATUS, val,
>> +					       val & (DDC_DONE | DDC_ERROR),
>> +					       20000, 250000);
>> +		if (ret && !(val & DDC_ERROR)) {
>> +			dev_err(it->dev, "failed to read EDID:%d\n", ret);
>> +			return ret;
>> +		}
>> +
>> +		if (val & DDC_ERROR) {
>> +			dev_err(it->dev, "DDC error\n");
>> +			return -EIO;
>> +		}
>> +
>> +		/* cache to buffer */
>> +		for (; count > 0; count--) {
>> +			regmap_read(regmap, HDMI_REG_DDC_READFIFO, &val);
>> +			*(buf++) = val;
>> +		}
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int it6263_connector_get_modes(struct drm_connector *connector)
>> +{
>> +	struct it6263 *it = connector_to_it6263(connector);
>> +	const struct drm_edid *drm_edid;
>> +	int count;
>> +
>> +	drm_edid = drm_edid_read_custom(connector, it6263_read_edid, it);
>> +
>> +	drm_edid_connector_update(connector, drm_edid);
>> +	count = drm_edid_connector_add_modes(connector);
>> +
>> +	drm_edid_free(drm_edid);
>> +
>> +	return count;
>> +}
>> +
>> +static const struct drm_connector_helper_funcs it6263_connector_helper_funcs = {
>> +	.get_modes = it6263_connector_get_modes, };
>> +
>> +static int it6263_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 *mode = &crtc_state->adjusted_mode;
>> +
>> +	return mode->clock > MAX_PIXEL_CLOCK_KHZ ? -EINVAL : 0; }
>> +
>> +static void
>> +it6263_bridge_atomic_disable(struct drm_bridge *bridge,
>> +			     struct drm_bridge_state *old_bridge_state) {
>> +	struct it6263 *it = bridge_to_it6263(bridge);
>> +
>> +	regmap_write_bits(it->hdmi_regmap, HDMI_REG_GCP, AVMUTE, AVMUTE);
>> +	regmap_write(it->hdmi_regmap, HDMI_REG_PKT_GENERAL_CTRL, 0);
>> +	regmap_write(it->hdmi_regmap, HDMI_REG_AFE_DRV_CTRL,
>> +		     AFE_DRV_RST | AFE_DRV_PWD);
>> +}
>> +
>> +static void
>> +it6263_bridge_atomic_enable(struct drm_bridge *bridge,
>> +			    struct drm_bridge_state *old_bridge_state) {
>> +	struct drm_atomic_state *state = old_bridge_state->base.state;
>> +	struct it6263 *it = bridge_to_it6263(bridge);
>> +	const struct drm_crtc_state *crtc_state;
>> +	struct regmap *regmap = it->hdmi_regmap;
>> +	const struct drm_display_mode *mode;
>> +	struct drm_connector *connector;
>> +	bool is_stable = false;
>> +	struct drm_crtc *crtc;
>> +	unsigned int val;
>> +	bool pclk_high;
>> +	int i, ret;
>> +
>> +	connector = drm_atomic_get_new_connector_for_encoder(state,
>> +							     bridge->encoder);
>> +	crtc = drm_atomic_get_new_connector_state(state, connector)->crtc;
>> +	crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
>> +	mode = &crtc_state->adjusted_mode;
>> +
>> +	regmap_write(regmap, HDMI_REG_HDMI_MODE, TX_HDMI_MODE);
>> +
>> +	/* HDMI AFE setup */
>> +	pclk_high = mode->clock > HIGH_PIXEL_CLOCK_KHZ ? true : false;
>> +	regmap_write(regmap, HDMI_REG_AFE_DRV_CTRL, AFE_DRV_RST);
>> +	if (pclk_high)
>> +		regmap_write(regmap, HDMI_REG_AFE_XP_CTRL,
>> +			     AFE_XP_GAINBIT | AFE_XP_RESETB);
>> +	else
>> +		regmap_write(regmap, HDMI_REG_AFE_XP_CTRL,
>> +			     AFE_XP_ER0 | AFE_XP_RESETB);
>> +	regmap_write(regmap, HDMI_REG_AFE_ISW_CTRL, 0x10);
>> +	if (pclk_high)
>> +		regmap_write(regmap, HDMI_REG_AFE_IP_CTRL,
>> +			     AFE_IP_GAINBIT | AFE_IP_RESETB);
>> +	else
>> +		regmap_write(regmap, HDMI_REG_AFE_IP_CTRL,
>> +			     AFE_IP_ER0 | AFE_IP_RESETB);
>> +
>> +	/* HDMI software video reset */
>> +	regmap_write_bits(regmap, HDMI_REG_SW_RST, SOFTV_RST, SOFTV_RST);
>> +	fsleep(1000);
>> +	regmap_write_bits(regmap, HDMI_REG_SW_RST, SOFTV_RST, 0);
>> +
>> +	/* reconfigure LVDS and retry several times in case video is instable */
>> +	for (i = 0; i < 3; i++) {
>> +		ret = regmap_read_poll_timeout(regmap, HDMI_REG_SYS_STATUS, val,
>> +					       val & TXVIDSTABLE,
>> +					       20000, 500000);
>> +		if (!ret) {
>> +			is_stable = true;
>> +			break;
>> +		}
>> +
>> +		it6263_lvds_config(it);
>> +	}
>> +
>> +	if (!is_stable)
>> +		dev_warn(it->dev, "failed to wait for video stable\n");
>> +
>> +	/* HDMI AFE reset release and power up */
>> +	regmap_write(regmap, HDMI_REG_AFE_DRV_CTRL, 0);
>> +
>> +	regmap_write_bits(regmap, HDMI_REG_GCP, AVMUTE, 0);
>> +
>> +	regmap_write(regmap, HDMI_REG_PKT_GENERAL_CTRL, ENABLE_PKT |
>> +REPEAT_PKT); }
>> +
>> +static enum drm_mode_status
>> +it6263_bridge_mode_valid(struct drm_bridge *bridge,
>> +			 const struct drm_display_info *info,
>> +			 const struct drm_display_mode *mode) {
>> +	return mode->clock > MAX_PIXEL_CLOCK_KHZ ? MODE_CLOCK_HIGH : MODE_OK;
>> +}
>> +
>> +static int it6263_bridge_attach(struct drm_bridge *bridge,
>> +				enum drm_bridge_attach_flags flags) {
>> +	struct it6263 *it = bridge_to_it6263(bridge);
>> +	int ret;
>> +
>> +	ret = drm_bridge_attach(bridge->encoder, it->next_bridge, bridge,
>> +				flags | DRM_BRIDGE_ATTACH_NO_CONNECTOR);
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
>> +		return 0;
>> +
>> +	it->connector.polled = DRM_CONNECTOR_POLL_CONNECT |
>> +			       DRM_CONNECTOR_POLL_DISCONNECT;
>> +
>> +	ret = drm_connector_init(bridge->dev, &it->connector,
>> +				 &it6263_connector_funcs,
>> +				 DRM_MODE_CONNECTOR_HDMIA);
>> +	if (ret)
>> +		return ret;
>> +
>> +	drm_connector_helper_add(&it->connector,
>> +				 &it6263_connector_helper_funcs);
>> +	drm_connector_attach_encoder(&it->connector, bridge->encoder);
>> +
>> +	return 0;
>> +}
>> +
>> +static enum drm_connector_status it6263_bridge_detect(struct drm_bridge
>> +*bridge) {
>> +	struct it6263 *it = bridge_to_it6263(bridge);
>> +
>> +	return it6263_detect(it);
>> +}
>> +
>> +static const struct drm_edid *
>> +it6263_bridge_edid_read(struct drm_bridge *bridge,
>> +			struct drm_connector *connector)
>> +{
>> +	struct it6263 *it = bridge_to_it6263(bridge);
>> +
>> +	return drm_edid_read_custom(connector, it6263_read_edid, it); }
>> +
>> +static u32 *
>> +it6263_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
>> +					struct drm_bridge_state *bridge_state,
>> +					struct drm_crtc_state *crtc_state,
>> +					struct drm_connector_state *conn_state,
>> +					u32 output_fmt,
>> +					unsigned int *num_input_fmts)
>> +{
>> +	u32 *input_fmts;
>> +
>> +	input_fmts = kmalloc(sizeof(*input_fmts), GFP_KERNEL);
>> +	if (!input_fmts) {
>> +		*num_input_fmts = 0;
>> +		return NULL;
>> +	}
>> +
>> +	input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA;
> 
> Why is it hardcoded? What about supporting VESA??
> 
>> +	*num_input_fmts = 1;
>> +
>> +	return input_fmts;
>> +}
>> +
>> +static const struct drm_bridge_funcs it6263_bridge_funcs = {
>> +	.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,
>> +	.attach = it6263_bridge_attach,
>> +	.mode_valid = it6263_bridge_mode_valid,
>> +	.atomic_disable = it6263_bridge_atomic_disable,
>> +	.atomic_enable = it6263_bridge_atomic_enable,
>> +	.atomic_check = it6263_bridge_atomic_check,
>> +	.detect = it6263_bridge_detect,
>> +	.edid_read = it6263_bridge_edid_read,
>> +	.atomic_get_input_bus_fmts = it6263_bridge_atomic_get_input_bus_fmts,
>> +};
>> +
>> +static int it6263_probe(struct i2c_client *client) {
>> +	struct device *dev = &client->dev;
>> +	struct it6263 *it;
>> +	int ret;
>> +
>> +	it = devm_kzalloc(dev, sizeof(*it), GFP_KERNEL);
>> +	if (!it)
>> +		return -ENOMEM;
>> +
>> +	it->dev = dev;
>> +	it->hdmi_i2c = client;
>> +
>> +	it->hdmi_regmap = devm_regmap_init_i2c(client,
>> +					       &it6263_hdmi_regmap_config);
>> +	if (IS_ERR(it->hdmi_regmap))
>> +		return dev_err_probe(dev, PTR_ERR(it->hdmi_regmap),
>> +				     "failed to init I2C regmap for HDMI\n");
>> +
>> +	it->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
>> +	if (IS_ERR(it->reset_gpio))
>> +		return dev_err_probe(dev, PTR_ERR(it->reset_gpio),
>> +				     "failed to get reset gpio\n");
>> +
>> +	ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(it6263_supplies),
>> +					     it6263_supplies);
>> +	if (ret)
>> +		return dev_err_probe(dev, ret, "failed to get power supplies\n");
>> +
>> +	ret = it6263_parse_dt(it);
>> +	if (ret)
>> +		return ret;
>> +
>> +	it6263_reset(it);
>> +
>> +	ret = it6263_lvds_set_i2c_addr(it);
>> +	if (ret)
>> +		return dev_err_probe(dev, ret, "failed to set I2C addr\n");
>> +
>> +	it->lvds_i2c = devm_i2c_new_dummy_device(dev, client->adapter,
>> +						 LVDS_INPUT_CTRL_I2C_ADDR);
>> +	if (IS_ERR(it->lvds_i2c))
>> +		dev_err_probe(it->dev, PTR_ERR(it->lvds_i2c),
>> +			      "failed to allocate I2C device for LVDS\n");
> 
> Maybe use action_or_reset and call i2c_unregister_device();

devm_i2c_new_dummy_device() is called here.  It is a dev managed function
call.  Action devm_i2c_release_dummy() is added in it already.

> 
>> +
>> +	it->lvds_regmap = devm_regmap_init_i2c(it->lvds_i2c,
>> +					       &it6263_lvds_regmap_config);
>> +	if (IS_ERR(it->lvds_regmap))
>> +		return dev_err_probe(dev, PTR_ERR(it->lvds_regmap),
>> +				     "failed to init I2C regmap for LVDS\n");
> 
>> +
>> +	it6263_lvds_config(it);
>> +	it6263_hdmi_config(it);
> 
>> +
>> +	i2c_set_clientdata(client, it);
>> +
>> +	it->bridge.funcs = &it6263_bridge_funcs;
>> +	it->bridge.of_node = dev->of_node;
>> +	it->bridge.ops = DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_DETECT;
> 
> 	it->bridge.type = DRM_MODE_CONNECTOR_HDMIA; ??

Will add this.  Thanks.

> 
>> +	drm_bridge_add(&it->bridge);
>> +
>> +	return 0;
>> +}
>> +
>> +static void it6263_remove(struct i2c_client *client) {
>> +	struct it6263 *it = i2c_get_clientdata(client);
>> +
>> +	drm_bridge_remove(&it->bridge);
> 
>> +}
>> +
>> +static const struct of_device_id it6263_of_match[] = {
>> +	{ .compatible = "ite,it6263", },
>> +	{ }
>> +};
>> +MODULE_DEVICE_TABLE(of, it6263_of_match);
>> +
>> +static const struct i2c_device_id it6263_i2c_ids[] = {
>> +	{ "it6263", 0 },
>> +	{ }
>> +};
>> +MODULE_DEVICE_TABLE(i2c, it6263_i2c_ids);
>> +
>> +static struct i2c_driver it6263_driver = {
>> +	.probe = it6263_probe,
>> +	.remove = it6263_remove,
>> +	.driver = {
>> +		.name = "it6263",
>> +		.of_match_table = it6263_of_match,
>> +	},
>> +	.id_table = it6263_i2c_ids,
>> +};
>> +module_i2c_driver(it6263_driver);
>> +
>> +MODULE_DESCRIPTION("ITE Tech. Inc. IT6263 LVDS/HDMI bridge");
>> +MODULE_AUTHOR("Liu Ying <victor.liu@nxp.com>"); MODULE_LICENSE("GPL");
>> --
>> 2.34.1
>>
> 

-- 
Regards,
Liu Ying


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

* RE: [PATCH 6/8] drm/bridge: Add ITE IT6263 LVDS to HDMI converter
  2024-09-30  9:40     ` Liu Ying
@ 2024-09-30  9:45       ` Biju Das
  0 siblings, 0 replies; 38+ messages in thread
From: Biju Das @ 2024-09-30  9:45 UTC (permalink / raw)
  To: Liu Ying, dri-devel@lists.freedesktop.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linux-arm-kernel@lists.infradead.org
  Cc: andrzej.hajda@intel.com, neil.armstrong@linaro.org,
	rfoss@kernel.org, laurent.pinchart, jonas@kwiboo.se,
	jernej.skrabec@gmail.com, maarten.lankhorst@linux.intel.com,
	mripard@kernel.org, tzimmermann@suse.de, airlied@gmail.com,
	simona@ffwll.ch, robh@kernel.org, krzk+dt@kernel.org,
	conor+dt@kernel.org, shawnguo@kernel.org, s.hauer@pengutronix.de,
	kernel@pengutronix.de, festevam@gmail.com,
	catalin.marinas@arm.com, will@kernel.org,
	quic_bjorande@quicinc.com, geert+renesas@glider.be,
	dmitry.baryshkov@linaro.org, arnd@arndb.de,
	nfraprado@collabora.com, o.rempel@pengutronix.de,
	y.moog@phytec.de

Hi Liu,

> -----Original Message-----
> From: Liu Ying <victor.liu@nxp.com>
> Sent: Monday, September 30, 2024 10:40 AM
> Subject: Re: [PATCH 6/8] drm/bridge: Add ITE IT6263 LVDS to HDMI converter
> 
> On 09/30/2024, Biju Das wrote:
> > Hi Liu,
> 
> Hi Biju,
> 
> >
> > Thanks for the patch.
> >
> >> -----Original Message-----
> >> From: linux-arm-kernel <linux-arm-kernel-bounces@lists.infradead.org>
> >> On Behalf Of Liu Ying
> >> Sent: Monday, September 30, 2024 6:29 AM
> >> Subject: [PATCH 6/8] drm/bridge: Add ITE IT6263 LVDS to HDMI
> >> converter
> >>
> >> Add basic HDMI video output support. Currently, only RGB888 output
> >> pixel format is supported.  At the LVDS input side, the driver
> >> supports single LVDS link and dual LVDS links with "jeida-24" LVDS mapping.
> >>
> >> Product link:
> >> https://www.ite.com.tw/en/product/cate1/IT6263
> >>
> >> Signed-off-by: Liu Ying <victor.liu@nxp.com>
> >> ---
> >>  drivers/gpu/drm/bridge/Kconfig      |   8 +
> >>  drivers/gpu/drm/bridge/Makefile     |   1 +
> >>  drivers/gpu/drm/bridge/ite-it6263.c | 829
> >> ++++++++++++++++++++++++++++
> >>  3 files changed, 838 insertions(+)
> >>  create mode 100644 drivers/gpu/drm/bridge/ite-it6263.c
> >>
> >> diff --git a/drivers/gpu/drm/bridge/Kconfig
> >> +
> >> +	it->lvds_i2c = devm_i2c_new_dummy_device(dev, client->adapter,
> >> +						 LVDS_INPUT_CTRL_I2C_ADDR);
> >> +	if (IS_ERR(it->lvds_i2c))
> >> +		dev_err_probe(it->dev, PTR_ERR(it->lvds_i2c),
> >> +			      "failed to allocate I2C device for LVDS\n");
> >
> > Maybe use action_or_reset and call i2c_unregister_device();
> 
> devm_i2c_new_dummy_device() is called here.  It is a dev managed function call.  Action
> devm_i2c_release_dummy() is added in it already.

Oops. I missed that.

Cheers,
Biju


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

* Re: [PATCH 5/8] dt-bindings: display: bridge: Add ITE IT6263 LVDS to HDMI converter
  2024-09-30  9:38           ` Biju Das
@ 2024-09-30  9:48             ` Liu Ying
  2024-09-30  9:53               ` Biju Das
  0 siblings, 1 reply; 38+ messages in thread
From: Liu Ying @ 2024-09-30  9:48 UTC (permalink / raw)
  To: Biju Das, dri-devel@lists.freedesktop.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linux-arm-kernel@lists.infradead.org
  Cc: andrzej.hajda@intel.com, neil.armstrong@linaro.org,
	rfoss@kernel.org, laurent.pinchart, jonas@kwiboo.se,
	jernej.skrabec@gmail.com, maarten.lankhorst@linux.intel.com,
	mripard@kernel.org, tzimmermann@suse.de, airlied@gmail.com,
	simona@ffwll.ch, robh@kernel.org, krzk+dt@kernel.org,
	conor+dt@kernel.org, shawnguo@kernel.org, s.hauer@pengutronix.de,
	kernel@pengutronix.de, festevam@gmail.com,
	catalin.marinas@arm.com, will@kernel.org,
	quic_bjorande@quicinc.com, geert+renesas@glider.be,
	dmitry.baryshkov@linaro.org, arnd@arndb.de,
	nfraprado@collabora.com, o.rempel@pengutronix.de,
	y.moog@phytec.de

On 09/30/2024, Biju Das wrote:
> Hi Liu,

Hi Biju,

> 
>> -----Original Message-----
>> From: Liu Ying <victor.liu@nxp.com>
>> Sent: Monday, September 30, 2024 10:30 AM
>> Subject: Re: [PATCH 5/8] dt-bindings: display: bridge: Add ITE IT6263 LVDS to HDMI converter
>>
>> On 09/30/2024, Biju Das wrote:
>>> Hi Liu,
>>
>> Hi Biju,
>>
>>>
>>>> -----Original Message-----
>>>> From: Liu Ying <victor.liu@nxp.com>
>>>> Sent: Monday, September 30, 2024 10:16 AM
>>>> Subject: Re: [PATCH 5/8] dt-bindings: display: bridge: Add ITE IT6263
>>>> LVDS to HDMI converter
>>>>
>>>> On 09/30/2024, Biju Das wrote:
>>>>> Hi Liu,
>>>>
>>>> Hi Biju,
>>>>
>>>>>
>>>>> thanks for the patch.
>>>>>
>>>>>> -----Original Message-----
>>>>>> From: linux-arm-kernel
>>>>>> <linux-arm-kernel-bounces@lists.infradead.org>
>>>>>> On Behalf Of Liu Ying
>>>>>> Sent: Monday, September 30, 2024 6:29 AM
>>>>>> Subject: [PATCH 5/8] dt-bindings: display: bridge: Add ITE IT6263
>>>>>> LVDS to HDMI converter
>>>>>>
>>>>>> Document ITE IT6263 LVDS to HDMI converter.
>>>>>>
>>>>>> Product link:
>>>>>> https://www.ite.com.tw/en/product/cate1/IT6263
>>>>>>
>>>>>> Signed-off-by: Liu Ying <victor.liu@nxp.com>
>>>>>> ---
>>>>>>  .../bindings/display/bridge/ite,it6263.yaml   | 310 ++++++++++++++++++
>>>>>>  1 file changed, 310 insertions(+)
>>>>>>  create mode 100644
>>>>>> Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml
>>>>>>
>>>>>> diff --git
>>>>>> a/Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml
>>>>>> b/Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml
>>>>>> new file mode 100644
>>>>>> index 000000000000..97fb81e5bc4a
>>>>>> --- /dev/null
>>>>>> +++ b/Documentation/devicetree/bindings/display/bridge/ite,it6263.y
>>>>>> +++ am
>>>>>> +++ l
>>>>>> @@ -0,0 +1,310 @@
>>>>>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML
>>>>>> +1.2
>>>>>> +---
>>>>>> +$id: http://devicetree.org/schemas/display/bridge/ite,it6263.yaml#
>>>>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>>>>> +
>>>>>> +title: ITE IT6263 LVDS to HDMI converter
>>>>>> +
>>>>>> +maintainers:
>>>>>> +  - Liu Ying <victor.liu@nxp.com>
>>>>>> +
>>>>>> +description: |
>>>>>> +  The IT6263 is a high-performance single-chip De-SSC(De-Spread
>>>>>> +Spectrum) LVDS
>>>>>> +  to HDMI converter.  Combined with LVDS receiver and HDMI 1.4a
>>>>>> +transmitter,
>>>>>> +  the IT6263 supports LVDS input and HDMI 1.4 output by conversion function.
>>>>>> +  The built-in LVDS receiver can support single-link and dual-link
>>>>>> +LVDS inputs,
>>>>>> +  and the built-in HDMI transmitter is fully compliant with HDMI
>>>>>> +1.4a/3D, HDCP
>>>>>> +  1.2 and backward compatible with DVI 1.0 specification.
>>>>>> +
>>>>>> +  The IT6263 also encodes and transmits up to 8 channels of I2S
>>>>>> + digital audio,  with sampling rate up to 192KHz and sample size up to 24 bits.
>>>>>> + In addition,  an S/PDIF input port takes in compressed audio of up to 192KHz frame rate.
>>>>>> +
>>>>>> +  The newly supported High-Bit Rate(HBR) audio by HDMI
>>>>>> + specifications
>>>>>> + v1.3 is  provided by the IT6263 in two interfaces: the four I2S
>>>>>> + input ports or the  S/PDIF input port.  With both interfaces the
>>>>>> + highest possible HBR frame rate  is supported at up to 768KHz.
>>>>>> +
>>>>>> +properties:
>>>>>> +  compatible:
>>>>>> +    const: ite,it6263
>>>>>> +
>>>>>> +  reg:
>>>>>> +    maxItems: 1
>>>>>> +
>>>>>> +  clocks:
>>>>>> +    maxItems: 1
>>>>>> +    description: audio master clock
>>>>>> +
>>>>>> +  clock-names:
>>>>>> +    const: mclk
>>>>>> +
>>>>>> +  reset-gpios:
>>>>>> +    maxItems: 1
>>>>>> +
>>>>>> +  ivdd-supply:
>>>>>> +    description: 1.8V digital logic power
>>>>>> +
>>>>>> +  ovdd-supply:
>>>>>> +    description: 3.3V I/O pin power
>>>>>> +
>>>>>> +  txavcc18-supply:
>>>>>> +    description: 1.8V HDMI analog frontend power
>>>>>> +
>>>>>> +  txavcc33-supply:
>>>>>> +    description: 3.3V HDMI analog frontend power
>>>>>> +
>>>>>> +  pvcc1-supply:
>>>>>> +    description: 1.8V HDMI frontend core PLL power
>>>>>> +
>>>>>> +  pvcc2-supply:
>>>>>> +    description: 1.8V HDMI frontend filter PLL power
>>>>>> +
>>>>>> +  avcc-supply:
>>>>>> +    description: 3.3V LVDS frontend power
>>>>>> +
>>>>>> +  anvdd-supply:
>>>>>> +    description: 1.8V LVDS frontend analog power
>>>>>> +
>>>>>> +  apvdd-supply:
>>>>>> +    description: 1.8V LVDS frontend PLL power
>>>>>> +
>>>>>> +  "#sound-dai-cells":
>>>>>> +    const: 0
>>>>>> +
>>>>>> +  ite,i2s-audio-fifo-sources:
>>>>>> +    $ref: /schemas/types.yaml#/definitions/uint32-array
>>>>>> +    minItems: 1
>>>>>> +    maxItems: 4
>>>>>> +    items:
>>>>>> +      enum: [0, 1, 2, 3]
>>>>>> +    description:
>>>>>> +      Each array element indicates the pin number of an I2S serial data input
>>>>>> +      line which is connected to an audio FIFO, from audio FIFO0 to FIFO3.
>>>>>> +
>>>>>> +  ite,rl-channel-swap-audio-sources:
>>>>>> +    $ref: /schemas/types.yaml#/definitions/uint32-array
>>>>>> +    minItems: 1
>>>>>> +    maxItems: 4
>>>>>> +    uniqueItems: true
>>>>>> +    items:
>>>>>> +      enum: [0, 1, 2, 3]
>>>>>> +    description:
>>>>>> +      Each array element indicates an audio source whose right channel and left
>>>>>> +      channel are swapped by this converter. For I2S, the element is the pin
>>>>>> +      number of an I2S serial data input line. For S/PDIF, the element is always
>>>>>> +      0.
>>>>>> +
>>>>>> +  ports:
>>>>>> +    $ref: /schemas/graph.yaml#/properties/ports
>>>>>> +
>>>>>> +    oneOf:
>>>>>> +      - properties:
>>>>>> +          port@0:
>>>>>> +            $ref: /schemas/graph.yaml#/properties/port
>>>>>> +            description: the first LVDS input link
>>>>>> +
>>>>>> +          port@1: false
>>>>>> +
>>>>>> +          port@2:
>>>>>> +            $ref: /schemas/graph.yaml#/properties/port
>>>>>> +            description: video port for the HDMI output
>>>>>> +
>>>>>> +          port@3:
>>>>>> +            $ref: /schemas/graph.yaml#/properties/port
>>>>>> +            description: sound input port
>>>>>> +
>>>>>> +        required:
>>>>>> +          - port@0
>>>>>> +          - port@2
>>>>>> +
>>>>>> +      - properties:
>>>>>> +          port@0:
>>>>>> +            $ref: /schemas/graph.yaml#/$defs/port-base
>>>>>> +            unevaluatedProperties: false
>>>>>> +            description: the first LVDS input link
>>>>>> +
>>>>>> +            properties:
>>>>>> +              dual-lvds-odd-pixels:
>>>>>> +                type: boolean
>>>>>> +                description: the first sink port for odd pixels
>>>>>> +
>>>>>> +              dual-lvds-even-pixels:
>>>>>> +                type: boolean
>>>>>> +                description: the first sink port for even pixels
>>>>>> +
>>>>>> +            oneOf:
>>>>>> +              - required: [dual-lvds-odd-pixels]
>>>>>> +              - required: [dual-lvds-even-pixels]
>>>>>> +
>>>>>> +          port@1:
>>>>>> +            $ref: /schemas/graph.yaml#/$defs/port-base
>>>>>> +            unevaluatedProperties: false
>>>>>> +            description: the second LVDS input link
>>>>>> +
>>>>>> +            properties:
>>>>>> +              dual-lvds-even-pixels:
>>>>>> +                type: boolean
>>>>>> +                description: the second sink port for even pixels
>>>>>> +
>>>>>> +              dual-lvds-odd-pixels:
>>>>>> +                type: boolean
>>>>>> +                description: the second sink port for odd pixels
>>>>>> +
>>>>>> +            oneOf:
>>>>>> +              - required: [dual-lvds-even-pixels]
>>>>>> +              - required: [dual-lvds-odd-pixels]
>>>>>
>>>>>
>>>>>> +
>>>>>> +          port@2:
>>>>>> +            $ref: /schemas/graph.yaml#/properties/port
>>>>>> +            description: video port for the HDMI output
>>>>>> +
>>>>>> +          port@3:
>>>>>> +            $ref: /schemas/graph.yaml#/properties/port
>>>>>> +            description: sound input port
>>>>>
>>>>> What about single lvds as device support it?
>>>>
>>>> The single LVDS link has already been documented in this binding doc.
>>>> Please find the "properties" above where only "port@0" and "port@2"
>>>> are required.
>>>
>>> Maybe "the first LVDS input link"-->"Single LVDS input link" for single LVDS block??
>>
>> Nope.
>>
>> I tested single LVDS link with the second LVDS link.  It didn't work.
>> The single LVDS link only works with the first LVDS link.
> 
> OK. That is the reason you made port@1 false.

Yes.

> 
> Still port@0 is a single LVDS instance or first LVDS input link for the dual
> LVDS configuration??

"port@0" always represents the first LVDS link and "port@1" always
represents the second LVDS link, no matter it's a single-link LVDS
or a dual-link LVDS.

Which one is the first/second LVDS link?  See "LVDS front-end
interface pin" in IT6263 data sheet[1] where first/second are
defined.

[1] http://static6.arrow.com/aropdfconversion/a2ecd2a29274cf0bfb3f3c829ef224c5838fe144/it6263fn.pdf

> 
> Cheers,
> Biju
> 
> 
>>
>>>
>>>>
>>>> imx8mp-evk-lvds0-imx-lvds-hdmi.dtso and
>>>> imx8mp-evk-lvds1-imx-lvds-hdmi.dtso
>>>> added in patch 7 support the NXP adapter card with single LVDS link.
>>>>
>>>>>
>>>>> Cheers,
>>>>> Biju
>>>>>
>>>>>> +
>>>>>> +        required:
>>>>>> +          - port@0
>>>>>> +          - port@1
>>>>>> +          - port@2
>>>>>> +
>>>>>> +        allOf:
>>>>>> +          - if:
>>>>>> +              properties:
>>>>>> +                port@0:
>>>>>> +                  required:
>>>>>> +                    - dual-lvds-odd-pixels
>>>>>> +            then:
>>>>>> +              properties:
>>>>>> +                port@1:
>>>>>> +                  properties:
>>>>>> +                    dual-lvds-odd-pixels: false
>>>>>> +
>>>>>> +          - if:
>>>>>> +              properties:
>>>>>> +                port@0:
>>>>>> +                  required:
>>>>>> +                    - dual-lvds-even-pixels
>>>>>> +            then:
>>>>>> +              properties:
>>>>>> +                port@1:
>>>>>> +                  properties:
>>>>>> +                    dual-lvds-even-pixels: false
>>>>>> +
>>>>>> +required:
>>>>>> +  - compatible
>>>>>> +  - reg
>>>>>> +  - ivdd-supply
>>>>>> +  - ovdd-supply
>>>>>> +  - txavcc18-supply
>>>>>> +  - txavcc33-supply
>>>>>> +  - pvcc1-supply
>>>>>> +  - pvcc2-supply
>>>>>> +  - avcc-supply
>>>>>> +  - anvdd-supply
>>>>>> +  - apvdd-supply
>>>>>> +  - ports
>>>>>> +
>>>>>> +additionalProperties: false
>>>>>> +
>>>>>> +examples:
>>>>>> +  - |
>>>>>> +    /* single-link LVDS input */
>>>>>> +    #include <dt-bindings/gpio/gpio.h>
>>>>>> +
>>>>>> +    i2c {
>>>>>> +        #address-cells = <1>;
>>>>>> +        #size-cells = <0>;
>>>>>> +
>>>>>> +        hdmi@4c {
>>>>>> +            compatible = "ite,it6263";
>>>>>> +            reg = <0x4c>;
>>>>>> +            reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
>>>>>> +            ivdd-supply = <&reg_buck5>;
>>>>>> +            ovdd-supply = <&reg_vext_3v3>;
>>>>>> +            txavcc18-supply = <&reg_buck5>;
>>>>>> +            txavcc33-supply = <&reg_vext_3v3>;
>>>>>> +            pvcc1-supply = <&reg_buck5>;
>>>>>> +            pvcc2-supply = <&reg_buck5>;
>>>>>> +            avcc-supply = <&reg_vext_3v3>;
>>>>>> +            anvdd-supply = <&reg_buck5>;
>>>>>> +            apvdd-supply = <&reg_buck5>;
>>>>>> +
>>>>>> +            ports {
>>>>>> +                #address-cells = <1>;
>>>>>> +                #size-cells = <0>;
>>>>>> +
>>>>>> +                port@0 {
>>>>>> +                    reg = <0>;
>>>>>> +
>>>>>> +                    it6263_lvds_link1: endpoint {
>>>>>> +                        remote-endpoint = <&ldb_lvds_ch0>;
>>>>>> +                    };
>>>>>> +                };
>>>>>> +
>>>>>> +                port@2 {
>>>>>> +                    reg = <2>;
>>>>>> +
>>>>>> +                    it6263_out: endpoint {
>>>>>> +                        remote-endpoint = <&hdmi_in>;
>>>>>> +                    };
>>>>>> +                };
>>>>>> +            };
>>>>>> +        };
>>>>>> +    };
>>>>>> +
>>>>>> +  - |
>>>>>> +    /* dual-link LVDS input */
>>>>>> +    #include <dt-bindings/gpio/gpio.h>
>>>>>> +
>>>>>> +    i2c {
>>>>>> +        #address-cells = <1>;
>>>>>> +        #size-cells = <0>;
>>>>>> +
>>>>>> +        hdmi@4c {
>>>>>> +            compatible = "ite,it6263";
>>>>>> +            reg = <0x4c>;
>>>>>> +            reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
>>>>>> +            ivdd-supply = <&reg_buck5>;
>>>>>> +            ovdd-supply = <&reg_vext_3v3>;
>>>>>> +            txavcc18-supply = <&reg_buck5>;
>>>>>> +            txavcc33-supply = <&reg_vext_3v3>;
>>>>>> +            pvcc1-supply = <&reg_buck5>;
>>>>>> +            pvcc2-supply = <&reg_buck5>;
>>>>>> +            avcc-supply = <&reg_vext_3v3>;
>>>>>> +            anvdd-supply = <&reg_buck5>;
>>>>>> +            apvdd-supply = <&reg_buck5>;
>>>>>> +
>>>>>> +            ports {
>>>>>> +                #address-cells = <1>;
>>>>>> +                #size-cells = <0>;
>>>>>> +
>>>>>> +                port@0 {
>>>>>> +                    reg = <0>;
>>>>>> +                    dual-lvds-odd-pixels;
>>>>>> +
>>>>>> +                    it6263_lvds_link1_dual: endpoint {
>>>>>> +                        remote-endpoint = <&ldb_lvds_ch0>;
>>>>>> +                    };
>>>>>> +                };
>>>>>> +
>>>>>> +                port@1 {
>>>>>> +                    reg = <1>;
>>>>>> +                    dual-lvds-even-pixels;
>>>>>> +
>>>>>> +                    it6263_lvds_link2_dual: endpoint {
>>>>>> +                        remote-endpoint = <&ldb_lvds_ch1>;
>>>>>> +                    };
>>>>>> +                };
>>>>>> +
>>>>>> +                port@2 {
>>>>>> +                    reg = <2>;
>>>>>> +
>>>>>> +                    it6263_out_dual: endpoint {
>>>>>> +                        remote-endpoint = <&hdmi_in>;
>>>>>> +                    };
>>>>>> +                };
>>>>>> +            };
>>>>>> +        };
>>>>>> +    };
>>>>>> --
>>>>>> 2.34.1
>>>>>>
>>>>>
>>>>
>>>> --
>>>> Regards,
>>>> Liu Ying
>>>
>>
>> --
>> Regards,
>> Liu Ying
> 

-- 
Regards,
Liu Ying


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

* RE: [PATCH 5/8] dt-bindings: display: bridge: Add ITE IT6263 LVDS to HDMI converter
  2024-09-30  9:48             ` Liu Ying
@ 2024-09-30  9:53               ` Biju Das
  0 siblings, 0 replies; 38+ messages in thread
From: Biju Das @ 2024-09-30  9:53 UTC (permalink / raw)
  To: Liu Ying, dri-devel@lists.freedesktop.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linux-arm-kernel@lists.infradead.org
  Cc: andrzej.hajda@intel.com, neil.armstrong@linaro.org,
	rfoss@kernel.org, laurent.pinchart, jonas@kwiboo.se,
	jernej.skrabec@gmail.com, maarten.lankhorst@linux.intel.com,
	mripard@kernel.org, tzimmermann@suse.de, airlied@gmail.com,
	simona@ffwll.ch, robh@kernel.org, krzk+dt@kernel.org,
	conor+dt@kernel.org, shawnguo@kernel.org, s.hauer@pengutronix.de,
	kernel@pengutronix.de, festevam@gmail.com,
	catalin.marinas@arm.com, will@kernel.org,
	quic_bjorande@quicinc.com, geert+renesas@glider.be,
	dmitry.baryshkov@linaro.org, arnd@arndb.de,
	nfraprado@collabora.com, o.rempel@pengutronix.de,
	y.moog@phytec.de

Hi Liu,

> -----Original Message-----
> From: Liu Ying <victor.liu@nxp.com>
> Sent: Monday, September 30, 2024 10:49 AM
> Subject: Re: [PATCH 5/8] dt-bindings: display: bridge: Add ITE IT6263 LVDS to HDMI converter
> 
> On 09/30/2024, Biju Das wrote:
> > Hi Liu,
> 
> Hi Biju,
> 
> >
> >> -----Original Message-----
> >> From: Liu Ying <victor.liu@nxp.com>
> >> Sent: Monday, September 30, 2024 10:30 AM
> >> Subject: Re: [PATCH 5/8] dt-bindings: display: bridge: Add ITE IT6263
> >> LVDS to HDMI converter
> >>
> >> On 09/30/2024, Biju Das wrote:
> >>> Hi Liu,
> >>
> >> Hi Biju,
> >>
> >>>
> >>>> -----Original Message-----
> >>>> From: Liu Ying <victor.liu@nxp.com>
> >>>> Sent: Monday, September 30, 2024 10:16 AM
> >>>> Subject: Re: [PATCH 5/8] dt-bindings: display: bridge: Add ITE
> >>>> IT6263 LVDS to HDMI converter
> >>>>
> >>>> On 09/30/2024, Biju Das wrote:
> >>>>> Hi Liu,
> >>>>
> >>>> Hi Biju,
> >>>>
> >>>>>
> >>>>> thanks for the patch.
> >>>>>
> >>>>>> -----Original Message-----
> >>>>>> From: linux-arm-kernel
> >>>>>> <linux-arm-kernel-bounces@lists.infradead.org>
> >>>>>> On Behalf Of Liu Ying
> >>>>>> Sent: Monday, September 30, 2024 6:29 AM
> >>>>>> Subject: [PATCH 5/8] dt-bindings: display: bridge: Add ITE IT6263
> >>>>>> LVDS to HDMI converter
> >>>>>>
> >>>>>> Document ITE IT6263 LVDS to HDMI converter.
> >>>>>>
> >>>>>> Product link:
> >>>>>> https://www.ite.com.tw/en/product/cate1/IT6263
> >>>>>>
> >>>>>> Signed-off-by: Liu Ying <victor.liu@nxp.com>
> >>>>>> ---
> >>>>>>  .../bindings/display/bridge/ite,it6263.yaml   | 310 ++++++++++++++++++
> >>>>>>  1 file changed, 310 insertions(+)  create mode 100644
> >>>>>> Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml
> >>>>>>
> >>>>>> diff --git
> >>>>>> a/Documentation/devicetree/bindings/display/bridge/ite,it6263.yam
> >>>>>> l
> >>>>>> b/Documentation/devicetree/bindings/display/bridge/ite,it6263.yam
> >>>>>> l
> >>>>>> new file mode 100644
> >>>>>> index 000000000000..97fb81e5bc4a
> >>>>>> --- /dev/null
> >>>>>> +++ b/Documentation/devicetree/bindings/display/bridge/ite,it6263
> >>>>>> +++ .y
> >>>>>> +++ am
> >>>>>> +++ l
> >>>>>> @@ -0,0 +1,310 @@
> >>>>>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML
> >>>>>> +1.2
> >>>>>> +---
> >>>>>> +$id:
> >>>>>> +http://devicetree.org/schemas/display/bridge/ite,it6263.yaml#
> >>>>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> >>>>>> +
> >>>>>> +title: ITE IT6263 LVDS to HDMI converter
> >>>>>> +
> >>>>>> +maintainers:
> >>>>>> +  - Liu Ying <victor.liu@nxp.com>
> >>>>>> +
> >>>>>> +description: |
> >>>>>> +  The IT6263 is a high-performance single-chip De-SSC(De-Spread
> >>>>>> +Spectrum) LVDS
> >>>>>> +  to HDMI converter.  Combined with LVDS receiver and HDMI 1.4a
> >>>>>> +transmitter,
> >>>>>> +  the IT6263 supports LVDS input and HDMI 1.4 output by conversion function.
> >>>>>> +  The built-in LVDS receiver can support single-link and
> >>>>>> +dual-link LVDS inputs,
> >>>>>> +  and the built-in HDMI transmitter is fully compliant with HDMI
> >>>>>> +1.4a/3D, HDCP
> >>>>>> +  1.2 and backward compatible with DVI 1.0 specification.
> >>>>>> +
> >>>>>> +  The IT6263 also encodes and transmits up to 8 channels of I2S
> >>>>>> + digital audio,  with sampling rate up to 192KHz and sample size up to 24 bits.
> >>>>>> + In addition,  an S/PDIF input port takes in compressed audio of up to 192KHz frame rate.
> >>>>>> +
> >>>>>> +  The newly supported High-Bit Rate(HBR) audio by HDMI
> >>>>>> + specifications
> >>>>>> + v1.3 is  provided by the IT6263 in two interfaces: the four I2S
> >>>>>> + input ports or the  S/PDIF input port.  With both interfaces
> >>>>>> + the highest possible HBR frame rate  is supported at up to 768KHz.
> >>>>>> +
> >>>>>> +properties:
> >>>>>> +  compatible:
> >>>>>> +    const: ite,it6263
> >>>>>> +
> >>>>>> +  reg:
> >>>>>> +    maxItems: 1
> >>>>>> +
> >>>>>> +  clocks:
> >>>>>> +    maxItems: 1
> >>>>>> +    description: audio master clock
> >>>>>> +
> >>>>>> +  clock-names:
> >>>>>> +    const: mclk
> >>>>>> +
> >>>>>> +  reset-gpios:
> >>>>>> +    maxItems: 1
> >>>>>> +
> >>>>>> +  ivdd-supply:
> >>>>>> +    description: 1.8V digital logic power
> >>>>>> +
> >>>>>> +  ovdd-supply:
> >>>>>> +    description: 3.3V I/O pin power
> >>>>>> +
> >>>>>> +  txavcc18-supply:
> >>>>>> +    description: 1.8V HDMI analog frontend power
> >>>>>> +
> >>>>>> +  txavcc33-supply:
> >>>>>> +    description: 3.3V HDMI analog frontend power
> >>>>>> +
> >>>>>> +  pvcc1-supply:
> >>>>>> +    description: 1.8V HDMI frontend core PLL power
> >>>>>> +
> >>>>>> +  pvcc2-supply:
> >>>>>> +    description: 1.8V HDMI frontend filter PLL power
> >>>>>> +
> >>>>>> +  avcc-supply:
> >>>>>> +    description: 3.3V LVDS frontend power
> >>>>>> +
> >>>>>> +  anvdd-supply:
> >>>>>> +    description: 1.8V LVDS frontend analog power
> >>>>>> +
> >>>>>> +  apvdd-supply:
> >>>>>> +    description: 1.8V LVDS frontend PLL power
> >>>>>> +
> >>>>>> +  "#sound-dai-cells":
> >>>>>> +    const: 0
> >>>>>> +
> >>>>>> +  ite,i2s-audio-fifo-sources:
> >>>>>> +    $ref: /schemas/types.yaml#/definitions/uint32-array
> >>>>>> +    minItems: 1
> >>>>>> +    maxItems: 4
> >>>>>> +    items:
> >>>>>> +      enum: [0, 1, 2, 3]
> >>>>>> +    description:
> >>>>>> +      Each array element indicates the pin number of an I2S serial data input
> >>>>>> +      line which is connected to an audio FIFO, from audio FIFO0 to FIFO3.
> >>>>>> +
> >>>>>> +  ite,rl-channel-swap-audio-sources:
> >>>>>> +    $ref: /schemas/types.yaml#/definitions/uint32-array
> >>>>>> +    minItems: 1
> >>>>>> +    maxItems: 4
> >>>>>> +    uniqueItems: true
> >>>>>> +    items:
> >>>>>> +      enum: [0, 1, 2, 3]
> >>>>>> +    description:
> >>>>>> +      Each array element indicates an audio source whose right channel and left
> >>>>>> +      channel are swapped by this converter. For I2S, the element is the pin
> >>>>>> +      number of an I2S serial data input line. For S/PDIF, the element is always
> >>>>>> +      0.
> >>>>>> +
> >>>>>> +  ports:
> >>>>>> +    $ref: /schemas/graph.yaml#/properties/ports
> >>>>>> +
> >>>>>> +    oneOf:
> >>>>>> +      - properties:
> >>>>>> +          port@0:
> >>>>>> +            $ref: /schemas/graph.yaml#/properties/port
> >>>>>> +            description: the first LVDS input link
> >>>>>> +
> >>>>>> +          port@1: false
> >>>>>> +
> >>>>>> +          port@2:
> >>>>>> +            $ref: /schemas/graph.yaml#/properties/port
> >>>>>> +            description: video port for the HDMI output
> >>>>>> +
> >>>>>> +          port@3:
> >>>>>> +            $ref: /schemas/graph.yaml#/properties/port
> >>>>>> +            description: sound input port
> >>>>>> +
> >>>>>> +        required:
> >>>>>> +          - port@0
> >>>>>> +          - port@2
> >>>>>> +
> >>>>>> +      - properties:
> >>>>>> +          port@0:
> >>>>>> +            $ref: /schemas/graph.yaml#/$defs/port-base
> >>>>>> +            unevaluatedProperties: false
> >>>>>> +            description: the first LVDS input link
> >>>>>> +
> >>>>>> +            properties:
> >>>>>> +              dual-lvds-odd-pixels:
> >>>>>> +                type: boolean
> >>>>>> +                description: the first sink port for odd pixels
> >>>>>> +
> >>>>>> +              dual-lvds-even-pixels:
> >>>>>> +                type: boolean
> >>>>>> +                description: the first sink port for even pixels
> >>>>>> +
> >>>>>> +            oneOf:
> >>>>>> +              - required: [dual-lvds-odd-pixels]
> >>>>>> +              - required: [dual-lvds-even-pixels]
> >>>>>> +
> >>>>>> +          port@1:
> >>>>>> +            $ref: /schemas/graph.yaml#/$defs/port-base
> >>>>>> +            unevaluatedProperties: false
> >>>>>> +            description: the second LVDS input link
> >>>>>> +
> >>>>>> +            properties:
> >>>>>> +              dual-lvds-even-pixels:
> >>>>>> +                type: boolean
> >>>>>> +                description: the second sink port for even
> >>>>>> + pixels
> >>>>>> +
> >>>>>> +              dual-lvds-odd-pixels:
> >>>>>> +                type: boolean
> >>>>>> +                description: the second sink port for odd pixels
> >>>>>> +
> >>>>>> +            oneOf:
> >>>>>> +              - required: [dual-lvds-even-pixels]
> >>>>>> +              - required: [dual-lvds-odd-pixels]
> >>>>>
> >>>>>
> >>>>>> +
> >>>>>> +          port@2:
> >>>>>> +            $ref: /schemas/graph.yaml#/properties/port
> >>>>>> +            description: video port for the HDMI output
> >>>>>> +
> >>>>>> +          port@3:
> >>>>>> +            $ref: /schemas/graph.yaml#/properties/port
> >>>>>> +            description: sound input port
> >>>>>
> >>>>> What about single lvds as device support it?
> >>>>
> >>>> The single LVDS link has already been documented in this binding doc.
> >>>> Please find the "properties" above where only "port@0" and "port@2"
> >>>> are required.
> >>>
> >>> Maybe "the first LVDS input link"-->"Single LVDS input link" for single LVDS block??
> >>
> >> Nope.
> >>
> >> I tested single LVDS link with the second LVDS link.  It didn't work.
> >> The single LVDS link only works with the first LVDS link.
> >
> > OK. That is the reason you made port@1 false.
> 
> Yes.
> 
> >
> > Still port@0 is a single LVDS instance or first LVDS input link for
> > the dual LVDS configuration??
> 
> "port@0" always represents the first LVDS link and "port@1" always represents the second LVDS link, no
> matter it's a single-link LVDS or a dual-link LVDS.
> 
> Which one is the first/second LVDS link?  See "LVDS front-end interface pin" in IT6263 data sheet[1]
> where first/second are defined.
> 
> [1] http://static6.arrow.com/aropdfconversion/a2ecd2a29274cf0bfb3f3c829ef224c5838fe144/it6263fn.pdf

I agree it matches with hw documentation.

Cheers,
Biju

> 
> >
> > Cheers,
> > Biju
> >
> >
> >>
> >>>
> >>>>
> >>>> imx8mp-evk-lvds0-imx-lvds-hdmi.dtso and
> >>>> imx8mp-evk-lvds1-imx-lvds-hdmi.dtso
> >>>> added in patch 7 support the NXP adapter card with single LVDS link.
> >>>>
> >>>>>
> >>>>> Cheers,
> >>>>> Biju
> >>>>>
> >>>>>> +
> >>>>>> +        required:
> >>>>>> +          - port@0
> >>>>>> +          - port@1
> >>>>>> +          - port@2
> >>>>>> +
> >>>>>> +        allOf:
> >>>>>> +          - if:
> >>>>>> +              properties:
> >>>>>> +                port@0:
> >>>>>> +                  required:
> >>>>>> +                    - dual-lvds-odd-pixels
> >>>>>> +            then:
> >>>>>> +              properties:
> >>>>>> +                port@1:
> >>>>>> +                  properties:
> >>>>>> +                    dual-lvds-odd-pixels: false
> >>>>>> +
> >>>>>> +          - if:
> >>>>>> +              properties:
> >>>>>> +                port@0:
> >>>>>> +                  required:
> >>>>>> +                    - dual-lvds-even-pixels
> >>>>>> +            then:
> >>>>>> +              properties:
> >>>>>> +                port@1:
> >>>>>> +                  properties:
> >>>>>> +                    dual-lvds-even-pixels: false
> >>>>>> +
> >>>>>> +required:
> >>>>>> +  - compatible
> >>>>>> +  - reg
> >>>>>> +  - ivdd-supply
> >>>>>> +  - ovdd-supply
> >>>>>> +  - txavcc18-supply
> >>>>>> +  - txavcc33-supply
> >>>>>> +  - pvcc1-supply
> >>>>>> +  - pvcc2-supply
> >>>>>> +  - avcc-supply
> >>>>>> +  - anvdd-supply
> >>>>>> +  - apvdd-supply
> >>>>>> +  - ports
> >>>>>> +
> >>>>>> +additionalProperties: false
> >>>>>> +
> >>>>>> +examples:
> >>>>>> +  - |
> >>>>>> +    /* single-link LVDS input */
> >>>>>> +    #include <dt-bindings/gpio/gpio.h>
> >>>>>> +
> >>>>>> +    i2c {
> >>>>>> +        #address-cells = <1>;
> >>>>>> +        #size-cells = <0>;
> >>>>>> +
> >>>>>> +        hdmi@4c {
> >>>>>> +            compatible = "ite,it6263";
> >>>>>> +            reg = <0x4c>;
> >>>>>> +            reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
> >>>>>> +            ivdd-supply = <&reg_buck5>;
> >>>>>> +            ovdd-supply = <&reg_vext_3v3>;
> >>>>>> +            txavcc18-supply = <&reg_buck5>;
> >>>>>> +            txavcc33-supply = <&reg_vext_3v3>;
> >>>>>> +            pvcc1-supply = <&reg_buck5>;
> >>>>>> +            pvcc2-supply = <&reg_buck5>;
> >>>>>> +            avcc-supply = <&reg_vext_3v3>;
> >>>>>> +            anvdd-supply = <&reg_buck5>;
> >>>>>> +            apvdd-supply = <&reg_buck5>;
> >>>>>> +
> >>>>>> +            ports {
> >>>>>> +                #address-cells = <1>;
> >>>>>> +                #size-cells = <0>;
> >>>>>> +
> >>>>>> +                port@0 {
> >>>>>> +                    reg = <0>;
> >>>>>> +
> >>>>>> +                    it6263_lvds_link1: endpoint {
> >>>>>> +                        remote-endpoint = <&ldb_lvds_ch0>;
> >>>>>> +                    };
> >>>>>> +                };
> >>>>>> +
> >>>>>> +                port@2 {
> >>>>>> +                    reg = <2>;
> >>>>>> +
> >>>>>> +                    it6263_out: endpoint {
> >>>>>> +                        remote-endpoint = <&hdmi_in>;
> >>>>>> +                    };
> >>>>>> +                };
> >>>>>> +            };
> >>>>>> +        };
> >>>>>> +    };
> >>>>>> +
> >>>>>> +  - |
> >>>>>> +    /* dual-link LVDS input */
> >>>>>> +    #include <dt-bindings/gpio/gpio.h>
> >>>>>> +
> >>>>>> +    i2c {
> >>>>>> +        #address-cells = <1>;
> >>>>>> +        #size-cells = <0>;
> >>>>>> +
> >>>>>> +        hdmi@4c {
> >>>>>> +            compatible = "ite,it6263";
> >>>>>> +            reg = <0x4c>;
> >>>>>> +            reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
> >>>>>> +            ivdd-supply = <&reg_buck5>;
> >>>>>> +            ovdd-supply = <&reg_vext_3v3>;
> >>>>>> +            txavcc18-supply = <&reg_buck5>;
> >>>>>> +            txavcc33-supply = <&reg_vext_3v3>;
> >>>>>> +            pvcc1-supply = <&reg_buck5>;
> >>>>>> +            pvcc2-supply = <&reg_buck5>;
> >>>>>> +            avcc-supply = <&reg_vext_3v3>;
> >>>>>> +            anvdd-supply = <&reg_buck5>;
> >>>>>> +            apvdd-supply = <&reg_buck5>;
> >>>>>> +
> >>>>>> +            ports {
> >>>>>> +                #address-cells = <1>;
> >>>>>> +                #size-cells = <0>;
> >>>>>> +
> >>>>>> +                port@0 {
> >>>>>> +                    reg = <0>;
> >>>>>> +                    dual-lvds-odd-pixels;
> >>>>>> +
> >>>>>> +                    it6263_lvds_link1_dual: endpoint {
> >>>>>> +                        remote-endpoint = <&ldb_lvds_ch0>;
> >>>>>> +                    };
> >>>>>> +                };
> >>>>>> +
> >>>>>> +                port@1 {
> >>>>>> +                    reg = <1>;
> >>>>>> +                    dual-lvds-even-pixels;
> >>>>>> +
> >>>>>> +                    it6263_lvds_link2_dual: endpoint {
> >>>>>> +                        remote-endpoint = <&ldb_lvds_ch1>;
> >>>>>> +                    };
> >>>>>> +                };
> >>>>>> +
> >>>>>> +                port@2 {
> >>>>>> +                    reg = <2>;
> >>>>>> +
> >>>>>> +                    it6263_out_dual: endpoint {
> >>>>>> +                        remote-endpoint = <&hdmi_in>;
> >>>>>> +                    };
> >>>>>> +                };
> >>>>>> +            };
> >>>>>> +        };
> >>>>>> +    };
> >>>>>> --
> >>>>>> 2.34.1
> >>>>>>
> >>>>>
> >>>>
> >>>> --
> >>>> Regards,
> >>>> Liu Ying
> >>>
> >>
> >> --
> >> Regards,
> >> Liu Ying
> >
> 
> --
> Regards,
> Liu Ying


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

* RE: [PATCH 6/8] drm/bridge: Add ITE IT6263 LVDS to HDMI converter
  2024-09-30  9:16   ` Biju Das
  2024-09-30  9:40     ` Liu Ying
@ 2024-09-30 13:10     ` Biju Das
  2024-10-09  8:33       ` Liu Ying
  1 sibling, 1 reply; 38+ messages in thread
From: Biju Das @ 2024-09-30 13:10 UTC (permalink / raw)
  To: Liu Ying, dri-devel@lists.freedesktop.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linux-arm-kernel@lists.infradead.org
  Cc: andrzej.hajda@intel.com, neil.armstrong@linaro.org,
	rfoss@kernel.org, laurent.pinchart, jonas@kwiboo.se,
	jernej.skrabec@gmail.com, maarten.lankhorst@linux.intel.com,
	mripard@kernel.org, tzimmermann@suse.de, airlied@gmail.com,
	simona@ffwll.ch, robh@kernel.org, krzk+dt@kernel.org,
	conor+dt@kernel.org, shawnguo@kernel.org, s.hauer@pengutronix.de,
	kernel@pengutronix.de, festevam@gmail.com,
	catalin.marinas@arm.com, will@kernel.org,
	quic_bjorande@quicinc.com, geert+renesas@glider.be,
	dmitry.baryshkov@linaro.org, arnd@arndb.de,
	nfraprado@collabora.com, o.rempel@pengutronix.de,
	y.moog@phytec.de

Hi Liu,

> -----Original Message-----
> From: Biju Das
> Sent: Monday, September 30, 2024 10:16 AM
> Subject: RE: [PATCH 6/8] drm/bridge: Add ITE IT6263 LVDS to HDMI converter
> 
> Hi Liu,
> 
> Thanks for the patch.
> 
> > -----Original Message-----
> > From: linux-arm-kernel <linux-arm-kernel-bounces@lists.infradead.org>
> > On Behalf Of Liu Ying
> > Sent: Monday, September 30, 2024 6:29 AM
> > Subject: [PATCH 6/8] drm/bridge: Add ITE IT6263 LVDS to HDMI converter
> >
> > Add basic HDMI video output support. Currently, only RGB888 output
> > pixel format is supported.  At the LVDS input side, the driver
> > supports single LVDS link and dual LVDS links with "jeida-24" LVDS mapping.
> >
> > Product link:
> > https://www.ite.com.tw/en/product/cate1/IT6263
> >
> > Signed-off-by: Liu Ying <victor.liu@nxp.com>
> > ---
> >  drivers/gpu/drm/bridge/Kconfig      |   8 +
> >  drivers/gpu/drm/bridge/Makefile     |   1 +
> >  drivers/gpu/drm/bridge/ite-it6263.c | 829
> > ++++++++++++++++++++++++++++
> >  3 files changed, 838 insertions(+)
> >  create mode 100644 drivers/gpu/drm/bridge/ite-it6263.c
> >
> > diff --git a/drivers/gpu/drm/bridge/Kconfig
> > b/drivers/gpu/drm/bridge/Kconfig index
> > 3eb955333c80..93f99682a090 100644
> > --- a/drivers/gpu/drm/bridge/Kconfig
> > +++ b/drivers/gpu/drm/bridge/Kconfig
> > @@ -90,6 +90,14 @@ config DRM_FSL_LDB
> >  	help
> >  	  Support for i.MX8MP DPI-to-LVDS on-SoC encoder.
> >
> > +config DRM_ITE_IT6263
> > +	tristate "ITE IT6263 LVDS/HDMI bridge"
> > +	depends on OF
> > +	select DRM_KMS_HELPER
> > +	select REGMAP_I2C
> > +	help
> > +	  ITE IT6263 LVDS to HDMI bridge chip driver.
> > +
> >  config DRM_ITE_IT6505
> >  	tristate "ITE IT6505 DisplayPort bridge"
> >  	depends on OF
> > diff --git a/drivers/gpu/drm/bridge/Makefile
> > b/drivers/gpu/drm/bridge/Makefile index 7df87b582dca..f3776dd473fd
> > 100644
> > --- a/drivers/gpu/drm/bridge/Makefile
> > +++ b/drivers/gpu/drm/bridge/Makefile
> > @@ -6,6 +6,7 @@ obj-$(CONFIG_DRM_CHRONTEL_CH7033) += chrontel-ch7033.o
> >  obj-$(CONFIG_DRM_CROS_EC_ANX7688) += cros-ec-anx7688.o
> >  obj-$(CONFIG_DRM_DISPLAY_CONNECTOR) += display-connector.o
> >  obj-$(CONFIG_DRM_FSL_LDB) += fsl-ldb.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
> >  obj-$(CONFIG_DRM_LONTIUM_LT9211) += lontium-lt9211.o diff --git
> > a/drivers/gpu/drm/bridge/ite-it6263.c
> > b/drivers/gpu/drm/bridge/ite-it6263.c
> > new file mode 100644
> > index 000000000000..886588497bc1
> > --- /dev/null
> > +++ b/drivers/gpu/drm/bridge/ite-it6263.c
> > @@ -0,0 +1,829 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright 2024 NXP
> > + */
> > +
> > +#include <linux/bitfield.h>
> > +#include <linux/bits.h>
> > +#include <linux/delay.h>
> > +#include <linux/gpio/consumer.h>
> > +#include <linux/i2c.h>
> > +#include <linux/media-bus-format.h>
> > +#include <linux/module.h>
> > +#include <linux/of.h>
> > +#include <linux/regmap.h>
> > +#include <linux/regulator/consumer.h>
> > +
> > +#include <drm/drm_atomic.h>
> > +#include <drm/drm_atomic_helper.h>
> > +#include <drm/drm_atomic_state_helper.h> #include <drm/drm_bridge.h>
> > +#include <drm/drm_connector.h> #include <drm/drm_crtc.h> #include
> > +<drm/drm_edid.h> #include <drm/drm_of.h> #include
> > +<drm/drm_probe_helper.h>
> > +
> > +/*
> > +---------------------------------------------------------------------
> > +--
> > +------
> > + * LVDS registers
> > + */
> > +
> > +/* LVDS software reset registers */
> > +#define LVDS_REG_05			0x05
> > +#define  REG_SOFT_P_RST			BIT(1)
> > +
> > +/* LVDS system configuration registers */
> > +/* 0x0b */
> > +#define LVDS_REG_0B			0x0b
> > +#define  REG_SSC_PCLK_RF		BIT(0)
> > +#define  REG_LVDS_IN_SWAP		BIT(1)
> > +
> > +/* LVDS test pattern gen control registers */
> > +/* 0x2c */
> > +#define LVDS_REG_2C			0x2c
> > +#define  REG_COL_DEP			GENMASK(1, 0)
> > +#define  BIT8				FIELD_PREP(REG_COL_DEP, 2)
> > +#define  OUT_MAP			BIT(4)
> > +#define  JEIDA				0
> > +#define  REG_DESSC_ENB			BIT(6)
> > +#define  DMODE				BIT(7)
> > +#define  DISO				BIT(7)
> > +#define  SISO				0
> > +
> > +#define LVDS_REG_3C			0x3c
> > +#define LVDS_REG_3F			0x3f
> > +#define LVDS_REG_47			0x47
> > +#define LVDS_REG_48			0x48
> > +#define LVDS_REG_4F			0x4f
> > +#define LVDS_REG_52			0x52
> > +
> > +/*
> > +---------------------------------------------------------------------
> > +--
> > +------
> > + * HDMI registers are separated into three banks:
> > + * 1) HDMI register common bank: 0x00 ~ 0x2f  */
> > +
> > +/* HDMI genernal registers */
> > +#define HDMI_REG_SW_RST			0x04
> > +#define  SOFTREF_RST			BIT(5)
> > +#define  SOFTA_RST			BIT(4)
> > +#define  SOFTV_RST			BIT(3)
> > +#define  AUD_RST			BIT(2)
> > +#define  HDCP_RST			BIT(0)
> > +#define  HDMI_RST_ALL			(SOFTREF_RST | SOFTA_RST | SOFTV_RST | \
> > +					 AUD_RST | HDCP_RST)
> > +
> > +#define HDMI_REG_SYS_STATUS		0x0e
> > +#define  HPDETECT			BIT(6)
> > +#define  TXVIDSTABLE			BIT(4)
> > +
> > +#define HDMI_REG_BANK_CTRL		0x0f
> > +#define  REG_BANK_SEL			BIT(0)
> > +
> > +/* HDMI System DDC control registers */
> > +#define HDMI_REG_DDC_MASTER_CTRL	0x10
> > +#define  MASTER_SEL_HOST		BIT(0)
> > +
> > +#define HDMI_REG_DDC_HEADER		0x11
> > +
> > +#define HDMI_REG_DDC_REQOFF		0x12
> > +#define HDMI_REG_DDC_REQCOUNT		0x13
> > +#define HDMI_REG_DDC_EDIDSEG		0x14
> > +
> > +#define HDMI_REG_DDC_CMD		0x15
> > +#define  DDC_CMD_EDID_READ		0x3
> > +#define  DDC_CMD_FIFO_CLR		0x9
> > +
> > +#define HDMI_REG_DDC_STATUS		0x16
> > +#define  DDC_DONE			BIT(7)
> > +#define  DDC_NOACK			BIT(5)
> > +#define  DDC_WAITBUS			BIT(4)
> > +#define  DDC_ARBILOSE			BIT(3)
> > +#define  DDC_ERROR			(DDC_NOACK | DDC_WAITBUS | DDC_ARBILOSE)
> > +
> > +#define HDMI_DDC_FIFO_BYTES		32
> > +#define HDMI_REG_DDC_READFIFO		0x17
> > +#define HDMI_REG_LVDS_PORT		0x1d /* LVDS input control I2C addr */
> > +#define HDMI_REG_LVDS_PORT_EN		0x1e
> > +#define LVDS_INPUT_CTRL_I2C_ADDR	0x33
> > +
> > +/*
> > +---------------------------------------------------------------------
> > +--
> > +------
> > + * 2) HDMI register bank0: 0x30 ~ 0xff  */
> > +
> > +/* HDMI AFE registers */
> > +#define HDMI_REG_AFE_DRV_CTRL		0x61
> > +#define  AFE_DRV_PWD			BIT(5)
> > +#define  AFE_DRV_RST			BIT(4)
> > +
> > +#define HDMI_REG_AFE_XP_CTRL		0x62
> > +#define  AFE_XP_GAINBIT			BIT(7)
> > +#define  AFE_XP_ER0			BIT(4)
> > +#define  AFE_XP_RESETB			BIT(3)
> > +
> > +#define HDMI_REG_AFE_ISW_CTRL		0x63
> > +
> > +#define HDMI_REG_AFE_IP_CTRL		0x64
> > +#define  AFE_IP_GAINBIT			BIT(7)
> > +#define  AFE_IP_ER0			BIT(3)
> > +#define  AFE_IP_RESETB			BIT(2)
> > +
> > +/* HDMI input data format registers */
> > +#define HDMI_REG_INPUT_MODE		0x70
> > +#define  IN_RGB				0x00
> > +
> > +/* HDMI general control registers */
> > +#define HDMI_REG_HDMI_MODE		0xc0
> > +#define  TX_HDMI_MODE			BIT(0)
> > +
> > +#define HDMI_REG_GCP			0xc1
> > +#define  AVMUTE				BIT(0)
> > +#define  HDMI_COLOR_DEPTH		GENMASK(6, 4)
> > +#define  HDMI_COLOR_DEPTH_24		FIELD_PREP(HDMI_COLOR_DEPTH, 4)
> > +
> > +#define HDMI_REG_PKT_GENERAL_CTRL	0xc6
> > +#define  ENABLE_PKT			BIT(0)
> > +#define  REPEAT_PKT			BIT(1)
> > +
> > +/*
> > +---------------------------------------------------------------------
> > +--
> > +------
> > + * 3) HDMI register bank1: 0x130 ~ 0x1ff (HDMI packet registers)  */
> > +
> > +/* AVI packet registers */
> > +#define HDMI_REG_AVI_DB1		0x158
> > +#define  AVI_DB1_COLOR_SPACE		GENMASK(6, 5)
> > +#define  AVI_COLOR_SPACE_RGB		FIELD_PREP(AVI_DB1_COLOR_SPACE, 0)
> > +
> > +#define MAX_PIXEL_CLOCK_KHZ		150000
> > +#define HIGH_PIXEL_CLOCK_KHZ		80000
> > +
> > +struct it6263 {
> > +	struct device *dev;
> > +	struct i2c_client *hdmi_i2c;
> > +	struct i2c_client *lvds_i2c;
> > +	struct regmap *hdmi_regmap;
> > +	struct regmap *lvds_regmap;
> > +	struct drm_bridge bridge;
> > +	struct drm_bridge *next_bridge;
> > +	struct drm_connector connector;
> > +	struct gpio_desc *reset_gpio;
> > +	bool lvds_dual_link;
> > +	bool lvds_link12_swap;
> > +};
> > +
> > +static inline struct it6263 *bridge_to_it6263(struct drm_bridge
> > +*bridge) {
> > +	return container_of(bridge, struct it6263, bridge); }
> > +
> > +static inline struct it6263 *connector_to_it6263(struct drm_connector
> > +*conn) {
> > +	return container_of(conn, struct it6263, connector); }
> > +
> > +static bool it6263_hdmi_writeable_reg(struct device *dev, unsigned
> > +int
> > +reg) {
> > +	switch (reg) {
> > +	case HDMI_REG_SW_RST:
> > +	case HDMI_REG_BANK_CTRL:
> > +	case HDMI_REG_DDC_MASTER_CTRL:
> > +	case HDMI_REG_DDC_HEADER:
> > +	case HDMI_REG_DDC_REQOFF:
> > +	case HDMI_REG_DDC_REQCOUNT:
> > +	case HDMI_REG_DDC_EDIDSEG:
> > +	case HDMI_REG_DDC_CMD:
> > +	case HDMI_REG_LVDS_PORT:
> > +	case HDMI_REG_LVDS_PORT_EN:
> > +	case HDMI_REG_AFE_DRV_CTRL:
> > +	case HDMI_REG_AFE_XP_CTRL:
> > +	case HDMI_REG_AFE_ISW_CTRL:
> > +	case HDMI_REG_AFE_IP_CTRL:
> > +	case HDMI_REG_INPUT_MODE:
> > +	case HDMI_REG_HDMI_MODE:
> > +	case HDMI_REG_GCP:
> > +	case HDMI_REG_PKT_GENERAL_CTRL:
> > +	case HDMI_REG_AVI_DB1:
> > +		return true;
> > +	default:
> > +		return false;
> > +	}
> > +}
> > +
> > +static bool it6263_hdmi_readable_reg(struct device *dev, unsigned int
> > +reg) {
> > +	if (it6263_hdmi_writeable_reg(dev, reg))
> > +		return true;
> > +
> > +	switch (reg) {
> > +	case HDMI_REG_SYS_STATUS:
> > +	case HDMI_REG_DDC_STATUS:
> > +	case HDMI_REG_DDC_READFIFO:
> > +		return true;
> > +	default:
> > +		return false;
> > +	}
> > +}
> > +
> > +static bool it6263_hdmi_volatile_reg(struct device *dev, unsigned int
> > +reg) {
> > +	switch (reg) {
> > +	case HDMI_REG_SW_RST:
> > +	case HDMI_REG_SYS_STATUS:
> > +	case HDMI_REG_DDC_STATUS:
> > +	case HDMI_REG_DDC_READFIFO:
> > +		return true;
> > +	default:
> > +		return false;
> > +	}
> > +}
> > +
> > +static const struct regmap_range_cfg it6263_hdmi_range_cfg = {
> > +	.range_min = 0x00,
> > +	.range_max = HDMI_REG_AVI_DB1,
> > +	.selector_reg = HDMI_REG_BANK_CTRL,
> > +	.selector_mask = REG_BANK_SEL,
> > +	.selector_shift = 0,
> > +	.window_start = 0x00,
> > +	.window_len = 0x100,
> > +};
> > +
> > +static const struct regmap_config it6263_hdmi_regmap_config = {
> > +	.name = "it6263-hdmi",
> > +	.reg_bits = 8,
> > +	.val_bits = 8,
> > +	.writeable_reg = it6263_hdmi_writeable_reg,
> > +	.readable_reg = it6263_hdmi_readable_reg,
> > +	.volatile_reg = it6263_hdmi_volatile_reg,
> > +	.max_register = HDMI_REG_AVI_DB1,
> > +	.ranges = &it6263_hdmi_range_cfg,
> > +	.num_ranges = 1,
> > +	.cache_type = REGCACHE_MAPLE,
> > +};
> > +
> > +static bool it6263_lvds_writeable_reg(struct device *dev, unsigned
> > +int
> > +reg) {
> > +	switch (reg) {
> > +	case LVDS_REG_05:
> > +	case LVDS_REG_0B:
> > +	case LVDS_REG_2C:
> > +	case LVDS_REG_3C:
> > +	case LVDS_REG_3F:
> > +	case LVDS_REG_47:
> > +	case LVDS_REG_48:
> > +	case LVDS_REG_4F:
> > +	case LVDS_REG_52:
> > +		return true;
> > +	default:
> > +		return false;
> > +	}
> > +}
> > +
> > +static bool it6263_lvds_readable_reg(struct device *dev, unsigned int
> > +reg) {
> > +	return it6263_lvds_writeable_reg(dev, reg); }
> > +
> > +static bool it6263_lvds_volatile_reg(struct device *dev, unsigned int
> > +reg) {
> > +	return reg == LVDS_REG_05;
> > +}
> > +
> > +static const struct regmap_config it6263_lvds_regmap_config = {
> > +	.name = "it6263-lvds",
> > +	.reg_bits = 8,
> > +	.val_bits = 8,
> > +	.writeable_reg = it6263_lvds_writeable_reg,
> > +	.readable_reg = it6263_lvds_readable_reg,
> > +	.volatile_reg = it6263_lvds_volatile_reg,
> > +	.max_register = LVDS_REG_52,
> > +	.cache_type = REGCACHE_MAPLE,
> > +};
> > +
> > +static const char * const it6263_supplies[] = {
> > +	"ivdd", "ovdd", "txavcc18", "txavcc33", "pvcc1", "pvcc2",
> > +	"avcc", "anvdd", "apvdd"
> > +};
> > +
> > +static int it6263_parse_dt(struct it6263 *it) {
> > +	struct device *dev = it->dev;
> > +	struct device_node *port0, *port1;
> > +	int ret = 0;
> > +
> > +	it->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 2, 0);
> > +	if (IS_ERR(it->next_bridge))
> > +		return dev_err_probe(dev, PTR_ERR(it->next_bridge),
> > +				     "failed to get next bridge\n");
> > +
> > +	port0 = of_graph_get_port_by_id(dev->of_node, 0);
> > +	port1 = of_graph_get_port_by_id(dev->of_node, 1);
> > +	if (port0 && port1) {
> > +		if (of_property_read_bool(port0, "dual-lvds-even-pixels") &&
> > +		    of_property_read_bool(port1, "dual-lvds-odd-pixels")) {
> > +			it->lvds_dual_link = true;
> > +			it->lvds_link12_swap = true;
> > +		} else if (of_property_read_bool(port0, "dual-lvds-odd-pixels") &&
> > +			   of_property_read_bool(port1, "dual-lvds-even-pixels")) {
> > +			it->lvds_dual_link = true;
> > +		}
> > +
> > +		if (!it->lvds_dual_link) {
> > +			dev_err(dev,
> > +				"failed to get LVDS dual link pixel order\n");
> > +			ret = -EINVAL;
> > +		}
> > +	} else if (port1) {
> > +		ret = -EINVAL;
> > +		dev_err(dev, "single input LVDS port1 is not supported\n");
> 
> 		Are you supporting single input LVDS port0??
> 
> > +	} else if (!port0) {
> > +		ret = -EINVAL;
> > +		dev_err(dev, "no input LVDS port\n");
> > +	}
> > +
> > +	of_node_put(port0);
> > +	of_node_put(port1);
> > +
> > +	return ret;
> > +}
> > +
> > +static inline void it6263_reset(struct it6263 *it) {
> > +	if (!it->reset_gpio)
> > +		return;
> > +
> > +	gpiod_set_value_cansleep(it->reset_gpio, 0);
> > +	fsleep(1000);
> > +	gpiod_set_value_cansleep(it->reset_gpio, 1);
> > +	/* The chip maker says the low pulse should be at least 40ms. */
> > +	fsleep(40000);
> > +	gpiod_set_value_cansleep(it->reset_gpio, 0);
> > +	/* addtional time to wait the high voltage to be stable */
> > +	fsleep(5000);
> 
> What about other resets ??
> 
> /* AFE PLL reset and  pclk reset */
> 
> > +}
> > +
> > +static inline int it6263_lvds_set_i2c_addr(struct it6263 *it) {
> > +	int ret;
> > +
> > +	ret = regmap_write(it->hdmi_regmap, HDMI_REG_LVDS_PORT,
> > +			   LVDS_INPUT_CTRL_I2C_ADDR << 1);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return regmap_write(it->hdmi_regmap, HDMI_REG_LVDS_PORT_EN, BIT(0));
> > +}
> > +
> > +static inline void it6263_lvds_reset(struct it6263 *it) {
> > +	/* AFE PLL reset */
> > +	regmap_write_bits(it->lvds_regmap, LVDS_REG_3C, BIT(0), 0x0);
> > +	fsleep(1000);
> > +	regmap_write_bits(it->lvds_regmap, LVDS_REG_3C, BIT(0), BIT(0));
> > +
> > +	/* software pixel clock domain reset */
> > +	regmap_write_bits(it->lvds_regmap, LVDS_REG_05, REG_SOFT_P_RST,
> > +			  REG_SOFT_P_RST);
> > +	fsleep(1000);
> > +	regmap_write_bits(it->lvds_regmap, LVDS_REG_05, REG_SOFT_P_RST, 0x0);
> > +	fsleep(10000);
> > +}
> > +
> > +static inline void it6263_lvds_set_interface(struct it6263 *it) {
> > +	/* color depth */
> > +	regmap_write_bits(it->lvds_regmap, LVDS_REG_2C, REG_COL_DEP, BIT8);
> > +	/* output mapping */
> > +	regmap_write_bits(it->lvds_regmap, LVDS_REG_2C, OUT_MAP, JEIDA);
> > +
> > +	if (it->lvds_dual_link) {
> > +		regmap_write_bits(it->lvds_regmap, LVDS_REG_2C, DMODE, DISO);
> > +		regmap_write_bits(it->lvds_regmap, LVDS_REG_52, BIT(1), BIT(1));
> > +	} else {
> > +		regmap_write_bits(it->lvds_regmap, LVDS_REG_2C, DMODE, SISO);
> > +		regmap_write_bits(it->lvds_regmap, LVDS_REG_52, BIT(1), 0);
> > +	}
> > +}
> > +
> > +static inline void it6263_lvds_set_afe(struct it6263 *it) {
> > +	regmap_write(it->lvds_regmap, LVDS_REG_3C, 0xaa);
> > +	regmap_write(it->lvds_regmap, LVDS_REG_3F, 0x02);
> > +	regmap_write(it->lvds_regmap, LVDS_REG_47, 0xaa);
> > +	regmap_write(it->lvds_regmap, LVDS_REG_48, 0x02);
> > +	regmap_write(it->lvds_regmap, LVDS_REG_4F, 0x11);
> > +
> > +	regmap_write_bits(it->lvds_regmap, LVDS_REG_0B, REG_SSC_PCLK_RF,
> > +			  REG_SSC_PCLK_RF);
> > +	regmap_write_bits(it->lvds_regmap, LVDS_REG_3C, 0x07, 0);
> > +	regmap_write_bits(it->lvds_regmap, LVDS_REG_2C, REG_DESSC_ENB,
> > +			  REG_DESSC_ENB);
> > +}
> > +
> > +static inline void it6263_lvds_sys_cfg(struct it6263 *it) {
> > +	regmap_write_bits(it->lvds_regmap, LVDS_REG_0B, REG_LVDS_IN_SWAP,
> > +			  it->lvds_link12_swap ? REG_LVDS_IN_SWAP : 0); }
> > +
> > +static inline void it6263_lvds_config(struct it6263 *it) {
> > +	it6263_lvds_reset(it);
> > +	it6263_lvds_set_interface(it);
> > +	it6263_lvds_set_afe(it);
> > +	it6263_lvds_sys_cfg(it);
> > +}
> > +
> > +static inline void it6263_hdmi_config(struct it6263 *it) {
> > +	regmap_write(it->hdmi_regmap, HDMI_REG_SW_RST, HDMI_RST_ALL);
> > +	regmap_write(it->hdmi_regmap, HDMI_REG_INPUT_MODE, IN_RGB);
> > +	regmap_write_bits(it->hdmi_regmap, HDMI_REG_GCP, HDMI_COLOR_DEPTH,
> > +			  HDMI_COLOR_DEPTH_24);
> > +	regmap_write_bits(it->hdmi_regmap, HDMI_REG_AVI_DB1,
> > +			  AVI_DB1_COLOR_SPACE, AVI_COLOR_SPACE_RGB); }
> > +
> > +static enum drm_connector_status it6263_detect(struct it6263 *it) {
> > +	unsigned int val;
> > +
> > +	regmap_read(it->hdmi_regmap, HDMI_REG_SYS_STATUS, &val);
> > +	if (val & HPDETECT)
> > +		return connector_status_connected;
> > +	else
> > +		return connector_status_disconnected; }
> > +
> > +static enum drm_connector_status
> > +it6263_connector_detect(struct drm_connector *connector, bool force) {
> > +	struct it6263 *it = connector_to_it6263(connector);
> > +
> > +	return it6263_detect(it);
> > +}
> > +
> > +static const struct drm_connector_funcs it6263_connector_funcs = {
> > +	.detect = it6263_connector_detect,
> > +	.fill_modes = drm_helper_probe_single_connector_modes,
> > +	.destroy = drm_connector_cleanup,
> > +	.reset = drm_atomic_helper_connector_reset,
> > +	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> > +	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> > +};
> > +
> > +static int it6263_read_edid(void *data, u8 *buf, unsigned int block,
> > +size_t len) {
> > +	struct it6263 *it = data;
> > +	struct regmap *regmap = it->hdmi_regmap;
> > +	unsigned int start = (block % 2) * EDID_LENGTH;
> > +	unsigned int segment = block >> 1;
> > +	unsigned int count, val;
> > +	int ret;
> > +
> > +	regmap_write(regmap, HDMI_REG_DDC_MASTER_CTRL, MASTER_SEL_HOST);
> > +	regmap_write(regmap, HDMI_REG_DDC_HEADER, DDC_ADDR << 1);
> > +	regmap_write(regmap, HDMI_REG_DDC_EDIDSEG, segment);
> > +
> > +	while (len) {
> > +		/* clear DDC FIFO */
> > +		regmap_write(regmap, HDMI_REG_DDC_CMD, DDC_CMD_FIFO_CLR);
> > +
> > +		ret = regmap_read_poll_timeout(regmap, HDMI_REG_DDC_STATUS,
> > +					       val, val & DDC_DONE,
> > +					       2000, 10000);
> > +		if (ret) {
> > +			dev_err(it->dev, "failed to clear DDC FIFO:%d\n", ret);
> > +			return ret;
> > +		}
> > +
> > +		count = len > HDMI_DDC_FIFO_BYTES ? HDMI_DDC_FIFO_BYTES : len;
> > +
> > +		/* fire the read command */
> > +		regmap_write(regmap, HDMI_REG_DDC_REQOFF, start);
> > +		regmap_write(regmap, HDMI_REG_DDC_REQCOUNT, count);
> > +		regmap_write(regmap, HDMI_REG_DDC_CMD, DDC_CMD_EDID_READ);
> > +
> > +		start += count;
> > +		len -= count;
> > +
> > +		ret = regmap_read_poll_timeout(regmap, HDMI_REG_DDC_STATUS, val,
> > +					       val & (DDC_DONE | DDC_ERROR),
> > +					       20000, 250000);
> > +		if (ret && !(val & DDC_ERROR)) {
> > +			dev_err(it->dev, "failed to read EDID:%d\n", ret);
> > +			return ret;
> > +		}
> > +
> > +		if (val & DDC_ERROR) {
> > +			dev_err(it->dev, "DDC error\n");
> > +			return -EIO;
> > +		}
> > +
> > +		/* cache to buffer */
> > +		for (; count > 0; count--) {
> > +			regmap_read(regmap, HDMI_REG_DDC_READFIFO, &val);
> > +			*(buf++) = val;
> > +		}
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int it6263_connector_get_modes(struct drm_connector
> > +*connector) {
> > +	struct it6263 *it = connector_to_it6263(connector);
> > +	const struct drm_edid *drm_edid;
> > +	int count;
> > +
> > +	drm_edid = drm_edid_read_custom(connector, it6263_read_edid, it);
> > +
> > +	drm_edid_connector_update(connector, drm_edid);
> > +	count = drm_edid_connector_add_modes(connector);
> > +
> > +	drm_edid_free(drm_edid);
> > +
> > +	return count;
> > +}
> > +
> > +static const struct drm_connector_helper_funcs it6263_connector_helper_funcs = {
> > +	.get_modes = it6263_connector_get_modes, };
> > +
> > +static int it6263_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 *mode = &crtc_state->adjusted_mode;
> > +
> > +	return mode->clock > MAX_PIXEL_CLOCK_KHZ ? -EINVAL : 0; }
> > +
> > +static void
> > +it6263_bridge_atomic_disable(struct drm_bridge *bridge,
> > +			     struct drm_bridge_state *old_bridge_state) {
> > +	struct it6263 *it = bridge_to_it6263(bridge);
> > +
> > +	regmap_write_bits(it->hdmi_regmap, HDMI_REG_GCP, AVMUTE, AVMUTE);
> > +	regmap_write(it->hdmi_regmap, HDMI_REG_PKT_GENERAL_CTRL, 0);
> > +	regmap_write(it->hdmi_regmap, HDMI_REG_AFE_DRV_CTRL,
> > +		     AFE_DRV_RST | AFE_DRV_PWD);
> > +}
> > +
> > +static void
> > +it6263_bridge_atomic_enable(struct drm_bridge *bridge,
> > +			    struct drm_bridge_state *old_bridge_state) {
> > +	struct drm_atomic_state *state = old_bridge_state->base.state;
> > +	struct it6263 *it = bridge_to_it6263(bridge);
> > +	const struct drm_crtc_state *crtc_state;
> > +	struct regmap *regmap = it->hdmi_regmap;
> > +	const struct drm_display_mode *mode;
> > +	struct drm_connector *connector;
> > +	bool is_stable = false;
> > +	struct drm_crtc *crtc;
> > +	unsigned int val;
> > +	bool pclk_high;
> > +	int i, ret;
> > +
> > +	connector = drm_atomic_get_new_connector_for_encoder(state,
> > +							     bridge->encoder);
> > +	crtc = drm_atomic_get_new_connector_state(state, connector)->crtc;
> > +	crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
> > +	mode = &crtc_state->adjusted_mode;
> > +
> > +	regmap_write(regmap, HDMI_REG_HDMI_MODE, TX_HDMI_MODE);
> > +
> > +	/* HDMI AFE setup */
> > +	pclk_high = mode->clock > HIGH_PIXEL_CLOCK_KHZ ? true : false;
> > +	regmap_write(regmap, HDMI_REG_AFE_DRV_CTRL, AFE_DRV_RST);
> > +	if (pclk_high)
> > +		regmap_write(regmap, HDMI_REG_AFE_XP_CTRL,
> > +			     AFE_XP_GAINBIT | AFE_XP_RESETB);
> > +	else
> > +		regmap_write(regmap, HDMI_REG_AFE_XP_CTRL,
> > +			     AFE_XP_ER0 | AFE_XP_RESETB);
> > +	regmap_write(regmap, HDMI_REG_AFE_ISW_CTRL, 0x10);
> > +	if (pclk_high)
> > +		regmap_write(regmap, HDMI_REG_AFE_IP_CTRL,
> > +			     AFE_IP_GAINBIT | AFE_IP_RESETB);
> > +	else
> > +		regmap_write(regmap, HDMI_REG_AFE_IP_CTRL,
> > +			     AFE_IP_ER0 | AFE_IP_RESETB);
> > +
> > +	/* HDMI software video reset */
> > +	regmap_write_bits(regmap, HDMI_REG_SW_RST, SOFTV_RST, SOFTV_RST);
> > +	fsleep(1000);
> > +	regmap_write_bits(regmap, HDMI_REG_SW_RST, SOFTV_RST, 0);
> > +
> > +	/* reconfigure LVDS and retry several times in case video is instable */
> > +	for (i = 0; i < 3; i++) {
> > +		ret = regmap_read_poll_timeout(regmap, HDMI_REG_SYS_STATUS, val,
> > +					       val & TXVIDSTABLE,
> > +					       20000, 500000);
> > +		if (!ret) {
> > +			is_stable = true;
> > +			break;
> > +		}
> > +
> > +		it6263_lvds_config(it);
> > +	}
> > +
> > +	if (!is_stable)
> > +		dev_warn(it->dev, "failed to wait for video stable\n");
> > +
> > +	/* HDMI AFE reset release and power up */
> > +	regmap_write(regmap, HDMI_REG_AFE_DRV_CTRL, 0);
> > +
> > +	regmap_write_bits(regmap, HDMI_REG_GCP, AVMUTE, 0);
> > +
> > +	regmap_write(regmap, HDMI_REG_PKT_GENERAL_CTRL, ENABLE_PKT |
> > +REPEAT_PKT); }
> > +
> > +static enum drm_mode_status
> > +it6263_bridge_mode_valid(struct drm_bridge *bridge,
> > +			 const struct drm_display_info *info,
> > +			 const struct drm_display_mode *mode) {
> > +	return mode->clock > MAX_PIXEL_CLOCK_KHZ ? MODE_CLOCK_HIGH :
> > +MODE_OK; }
> > +
> > +static int it6263_bridge_attach(struct drm_bridge *bridge,
> > +				enum drm_bridge_attach_flags flags) {
> > +	struct it6263 *it = bridge_to_it6263(bridge);
> > +	int ret;
> > +
> > +	ret = drm_bridge_attach(bridge->encoder, it->next_bridge, bridge,
> > +				flags | DRM_BRIDGE_ATTACH_NO_CONNECTOR);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
> > +		return 0;
> > +
> > +	it->connector.polled = DRM_CONNECTOR_POLL_CONNECT |
> > +			       DRM_CONNECTOR_POLL_DISCONNECT;
> > +
> > +	ret = drm_connector_init(bridge->dev, &it->connector,
> > +				 &it6263_connector_funcs,
> > +				 DRM_MODE_CONNECTOR_HDMIA);
> > +	if (ret)
> > +		return ret;
> > +
> > +	drm_connector_helper_add(&it->connector,
> > +				 &it6263_connector_helper_funcs);
> > +	drm_connector_attach_encoder(&it->connector, bridge->encoder);
> > +
> > +	return 0;
> > +}
> > +
> > +static enum drm_connector_status it6263_bridge_detect(struct
> > +drm_bridge
> > +*bridge) {
> > +	struct it6263 *it = bridge_to_it6263(bridge);
> > +
> > +	return it6263_detect(it);
> > +}
> > +
> > +static const struct drm_edid *
> > +it6263_bridge_edid_read(struct drm_bridge *bridge,
> > +			struct drm_connector *connector)
> > +{
> > +	struct it6263 *it = bridge_to_it6263(bridge);
> > +
> > +	return drm_edid_read_custom(connector, it6263_read_edid, it); }
> > +
> > +static u32 *
> > +it6263_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
> > +					struct drm_bridge_state *bridge_state,
> > +					struct drm_crtc_state *crtc_state,
> > +					struct drm_connector_state *conn_state,
> > +					u32 output_fmt,
> > +					unsigned int *num_input_fmts)
> > +{
> > +	u32 *input_fmts;
> > +
> > +	input_fmts = kmalloc(sizeof(*input_fmts), GFP_KERNEL);
> > +	if (!input_fmts) {
> > +		*num_input_fmts = 0;
> > +		return NULL;
> > +	}
> > +
> > +	input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA;
> 
> Why is it hardcoded? What about supporting VESA??
> 
> > +	*num_input_fmts = 1;
> > +
> > +	return input_fmts;
> > +}
> > +
> > +static const struct drm_bridge_funcs it6263_bridge_funcs = {
> > +	.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,
> > +	.attach = it6263_bridge_attach,
> > +	.mode_valid = it6263_bridge_mode_valid,
> > +	.atomic_disable = it6263_bridge_atomic_disable,
> > +	.atomic_enable = it6263_bridge_atomic_enable,
> > +	.atomic_check = it6263_bridge_atomic_check,
> > +	.detect = it6263_bridge_detect,
> > +	.edid_read = it6263_bridge_edid_read,
> > +	.atomic_get_input_bus_fmts =
> > +it6263_bridge_atomic_get_input_bus_fmts,
> > +};

Like [1]
static const struct drm_bridge_funcs it6263_bridge_funcs = {
	.attach = it6263_bridge_attach,
	.mode_set = it6263_bridge_mode_set,
	.disable = it6263_bridge_disable,
	.enable = it6263_bridge_enable,
	.get_edid = it6263_bridge_get_edid,
	.detect = it6263_bridge_detect,
};

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c?h=v6.12-rc1#n998

Is it not sufficient for your use case??

Cheers,
Biju

> > +
> > +static int it6263_probe(struct i2c_client *client) {
> > +	struct device *dev = &client->dev;
> > +	struct it6263 *it;
> > +	int ret;
> > +
> > +	it = devm_kzalloc(dev, sizeof(*it), GFP_KERNEL);
> > +	if (!it)
> > +		return -ENOMEM;
> > +
> > +	it->dev = dev;
> > +	it->hdmi_i2c = client;
> > +
> > +	it->hdmi_regmap = devm_regmap_init_i2c(client,
> > +					       &it6263_hdmi_regmap_config);
> > +	if (IS_ERR(it->hdmi_regmap))
> > +		return dev_err_probe(dev, PTR_ERR(it->hdmi_regmap),
> > +				     "failed to init I2C regmap for HDMI\n");
> > +
> > +	it->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
> > +	if (IS_ERR(it->reset_gpio))
> > +		return dev_err_probe(dev, PTR_ERR(it->reset_gpio),
> > +				     "failed to get reset gpio\n");
> > +
> > +	ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(it6263_supplies),
> > +					     it6263_supplies);
> > +	if (ret)
> > +		return dev_err_probe(dev, ret, "failed to get power supplies\n");
> > +
> > +	ret = it6263_parse_dt(it);
> > +	if (ret)
> > +		return ret;
> > +
> > +	it6263_reset(it);
> > +
> > +	ret = it6263_lvds_set_i2c_addr(it);
> > +	if (ret)
> > +		return dev_err_probe(dev, ret, "failed to set I2C addr\n");
> > +
> > +	it->lvds_i2c = devm_i2c_new_dummy_device(dev, client->adapter,
> > +						 LVDS_INPUT_CTRL_I2C_ADDR);
> > +	if (IS_ERR(it->lvds_i2c))
> > +		dev_err_probe(it->dev, PTR_ERR(it->lvds_i2c),
> > +			      "failed to allocate I2C device for LVDS\n");
> 
> Maybe use action_or_reset and call i2c_unregister_device();
> 
> > +
> > +	it->lvds_regmap = devm_regmap_init_i2c(it->lvds_i2c,
> > +					       &it6263_lvds_regmap_config);
> > +	if (IS_ERR(it->lvds_regmap))
> > +		return dev_err_probe(dev, PTR_ERR(it->lvds_regmap),
> > +				     "failed to init I2C regmap for LVDS\n");
> 
> > +
> > +	it6263_lvds_config(it);
> > +	it6263_hdmi_config(it);
> 
> > +
> > +	i2c_set_clientdata(client, it);
> > +
> > +	it->bridge.funcs = &it6263_bridge_funcs;
> > +	it->bridge.of_node = dev->of_node;
> > +	it->bridge.ops = DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_DETECT;
> 
> 	it->bridge.type = DRM_MODE_CONNECTOR_HDMIA; ??
> 
> > +	drm_bridge_add(&it->bridge);
> > +
> > +	return 0;
> > +}
> > +
> > +static void it6263_remove(struct i2c_client *client) {
> > +	struct it6263 *it = i2c_get_clientdata(client);
> > +
> > +	drm_bridge_remove(&it->bridge);
> 
> > +}
> > +
> > +static const struct of_device_id it6263_of_match[] = {
> > +	{ .compatible = "ite,it6263", },
> > +	{ }
> > +};
> > +MODULE_DEVICE_TABLE(of, it6263_of_match);
> > +
> > +static const struct i2c_device_id it6263_i2c_ids[] = {
> > +	{ "it6263", 0 },
> > +	{ }
> > +};
> > +MODULE_DEVICE_TABLE(i2c, it6263_i2c_ids);
> > +
> > +static struct i2c_driver it6263_driver = {
> > +	.probe = it6263_probe,
> > +	.remove = it6263_remove,
> > +	.driver = {
> > +		.name = "it6263",
> > +		.of_match_table = it6263_of_match,
> > +	},
> > +	.id_table = it6263_i2c_ids,
> > +};
> > +module_i2c_driver(it6263_driver);
> > +
> > +MODULE_DESCRIPTION("ITE Tech. Inc. IT6263 LVDS/HDMI bridge");
> > +MODULE_AUTHOR("Liu Ying <victor.liu@nxp.com>");
> > +MODULE_LICENSE("GPL");
> > --
> > 2.34.1
> >


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

* RE: [PATCH 5/8] dt-bindings: display: bridge: Add ITE IT6263 LVDS to HDMI converter
  2024-09-30  9:04   ` Biju Das
  2024-09-30  9:16     ` Liu Ying
@ 2024-09-30 13:18     ` Biju Das
  2024-10-09  7:51       ` Liu Ying
  1 sibling, 1 reply; 38+ messages in thread
From: Biju Das @ 2024-09-30 13:18 UTC (permalink / raw)
  To: Liu Ying, dri-devel@lists.freedesktop.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linux-arm-kernel@lists.infradead.org
  Cc: andrzej.hajda@intel.com, neil.armstrong@linaro.org,
	rfoss@kernel.org, laurent.pinchart, jonas@kwiboo.se,
	jernej.skrabec@gmail.com, maarten.lankhorst@linux.intel.com,
	mripard@kernel.org, tzimmermann@suse.de, airlied@gmail.com,
	simona@ffwll.ch, robh@kernel.org, krzk+dt@kernel.org,
	conor+dt@kernel.org, shawnguo@kernel.org, s.hauer@pengutronix.de,
	kernel@pengutronix.de, festevam@gmail.com,
	catalin.marinas@arm.com, will@kernel.org,
	quic_bjorande@quicinc.com, geert+renesas@glider.be,
	dmitry.baryshkov@linaro.org, arnd@arndb.de,
	nfraprado@collabora.com, o.rempel@pengutronix.de,
	y.moog@phytec.de

Hi Liu,

> -----Original Message-----
> From: Biju Das
> Sent: Monday, September 30, 2024 10:04 AM
> Subject: RE: [PATCH 5/8] dt-bindings: display: bridge: Add ITE IT6263 LVDS to HDMI converter
> 
> Hi Liu,
> 
> thanks for the patch.
> 
> > -----Original Message-----
> > From: linux-arm-kernel <linux-arm-kernel-bounces@lists.infradead.org>
> > On Behalf Of Liu Ying
> > Sent: Monday, September 30, 2024 6:29 AM
> > Subject: [PATCH 5/8] dt-bindings: display: bridge: Add ITE IT6263 LVDS
> > to HDMI converter
> >
> > Document ITE IT6263 LVDS to HDMI converter.
> >
> > Product link:
> > https://www.ite.com.tw/en/product/cate1/IT6263
> >
> > Signed-off-by: Liu Ying <victor.liu@nxp.com>
> > ---
> >  .../bindings/display/bridge/ite,it6263.yaml   | 310 ++++++++++++++++++
> >  1 file changed, 310 insertions(+)
> >  create mode 100644
> > Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml
> >
> > diff --git
> > a/Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml
> > b/Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml
> > new file mode 100644
> > index 000000000000..97fb81e5bc4a
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml
> > @@ -0,0 +1,310 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/display/bridge/ite,it6263.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: ITE IT6263 LVDS to HDMI converter
> > +
> > +maintainers:
> > +  - Liu Ying <victor.liu@nxp.com>
> > +
> > +description: |
> > +  The IT6263 is a high-performance single-chip De-SSC(De-Spread
> > +Spectrum) LVDS
> > +  to HDMI converter.  Combined with LVDS receiver and HDMI 1.4a
> > +transmitter,
> > +  the IT6263 supports LVDS input and HDMI 1.4 output by conversion function.
> > +  The built-in LVDS receiver can support single-link and dual-link
> > +LVDS inputs,
> > +  and the built-in HDMI transmitter is fully compliant with HDMI
> > +1.4a/3D, HDCP
> > +  1.2 and backward compatible with DVI 1.0 specification.
> > +
> > +  The IT6263 also encodes and transmits up to 8 channels of I2S
> > + digital audio,  with sampling rate up to 192KHz and sample size up to 24 bits.
> > + In addition,  an S/PDIF input port takes in compressed audio of up to 192KHz frame rate.
> > +
> > +  The newly supported High-Bit Rate(HBR) audio by HDMI specifications
> > + v1.3 is  provided by the IT6263 in two interfaces: the four I2S
> > + input ports or the  S/PDIF input port.  With both interfaces the
> > + highest possible HBR frame rate  is supported at up to 768KHz.
> > +
> > +properties:
> > +  compatible:
> > +    const: ite,it6263
> > +
> > +  reg:
> > +    maxItems: 1
> > +
> > +  clocks:
> > +    maxItems: 1
> > +    description: audio master clock
> > +
> > +  clock-names:
> > +    const: mclk
> > +
> > +  reset-gpios:
> > +    maxItems: 1
> > +
> > +  ivdd-supply:
> > +    description: 1.8V digital logic power
> > +
> > +  ovdd-supply:
> > +    description: 3.3V I/O pin power
> > +
> > +  txavcc18-supply:
> > +    description: 1.8V HDMI analog frontend power
> > +
> > +  txavcc33-supply:
> > +    description: 3.3V HDMI analog frontend power
> > +
> > +  pvcc1-supply:
> > +    description: 1.8V HDMI frontend core PLL power
> > +
> > +  pvcc2-supply:
> > +    description: 1.8V HDMI frontend filter PLL power
> > +
> > +  avcc-supply:
> > +    description: 3.3V LVDS frontend power
> > +
> > +  anvdd-supply:
> > +    description: 1.8V LVDS frontend analog power
> > +
> > +  apvdd-supply:
> > +    description: 1.8V LVDS frontend PLL power
> > +
> > +  "#sound-dai-cells":
> > +    const: 0
> > +
> > +  ite,i2s-audio-fifo-sources:
> > +    $ref: /schemas/types.yaml#/definitions/uint32-array
> > +    minItems: 1
> > +    maxItems: 4
> > +    items:
> > +      enum: [0, 1, 2, 3]
> > +    description:
> > +      Each array element indicates the pin number of an I2S serial data input
> > +      line which is connected to an audio FIFO, from audio FIFO0 to FIFO3.
> > +
> > +  ite,rl-channel-swap-audio-sources:
> > +    $ref: /schemas/types.yaml#/definitions/uint32-array
> > +    minItems: 1
> > +    maxItems: 4
> > +    uniqueItems: true
> > +    items:
> > +      enum: [0, 1, 2, 3]
> > +    description:
> > +      Each array element indicates an audio source whose right channel and left
> > +      channel are swapped by this converter. For I2S, the element is the pin
> > +      number of an I2S serial data input line. For S/PDIF, the element is always
> > +      0.
> > +
> > +  ports:
> > +    $ref: /schemas/graph.yaml#/properties/ports
> > +
> > +    oneOf:
> > +      - properties:
> > +          port@0:
> > +            $ref: /schemas/graph.yaml#/properties/port
> > +            description: the first LVDS input link
> > +
> > +          port@1: false
> > +
> > +          port@2:
> > +            $ref: /schemas/graph.yaml#/properties/port
> > +            description: video port for the HDMI output
> > +
> > +          port@3:
> > +            $ref: /schemas/graph.yaml#/properties/port
> > +            description: sound input port
> > +
> > +        required:
> > +          - port@0
> > +          - port@2
> > +
> > +      - properties:
> > +          port@0:
> > +            $ref: /schemas/graph.yaml#/$defs/port-base
> > +            unevaluatedProperties: false
> > +            description: the first LVDS input link
> > +
> > +            properties:
> > +              dual-lvds-odd-pixels:
> > +                type: boolean
> > +                description: the first sink port for odd pixels
> > +
> > +              dual-lvds-even-pixels:
> > +                type: boolean
> > +                description: the first sink port for even pixels
> > +
> > +            oneOf:
> > +              - required: [dual-lvds-odd-pixels]
> > +              - required: [dual-lvds-even-pixels]
> > +
> > +          port@1:
> > +            $ref: /schemas/graph.yaml#/$defs/port-base
> > +            unevaluatedProperties: false
> > +            description: the second LVDS input link
> > +
> > +            properties:
> > +              dual-lvds-even-pixels:
> > +                type: boolean
> > +                description: the second sink port for even pixels
> > +
> > +              dual-lvds-odd-pixels:
> > +                type: boolean
> > +                description: the second sink port for odd pixels
> > +
> > +            oneOf:
> > +              - required: [dual-lvds-even-pixels]
> > +              - required: [dual-lvds-odd-pixels]
> 
> 
> > +
> > +          port@2:
> > +            $ref: /schemas/graph.yaml#/properties/port
> > +            description: video port for the HDMI output
> > +
> > +          port@3:
> > +            $ref: /schemas/graph.yaml#/properties/port
> > +            description: sound input port
> 
> What about single lvds as device support it?
> 
> Cheers,
> Biju
> 
> > +
> > +        required:
> > +          - port@0
> > +          - port@1
> > +          - port@2
> > +
> > +        allOf:
> > +          - if:
> > +              properties:
> > +                port@0:
> > +                  required:
> > +                    - dual-lvds-odd-pixels
> > +            then:
> > +              properties:
> > +                port@1:
> > +                  properties:
> > +                    dual-lvds-odd-pixels: false
> > +
> > +          - if:
> > +              properties:
> > +                port@0:
> > +                  required:
> > +                    - dual-lvds-even-pixels
> > +            then:
> > +              properties:
> > +                port@1:
> > +                  properties:
> > +                    dual-lvds-even-pixels: false

Do we need to document ite,data-mapping to support both VESA and JEIDA formats??

Or

Is there any run time info available to get this info? Currently,
I see it is hardcoded in driver.

Cheers,
Biju

> > +
> > +required:
> > +  - compatible
> > +  - reg
> > +  - ivdd-supply
> > +  - ovdd-supply
> > +  - txavcc18-supply
> > +  - txavcc33-supply
> > +  - pvcc1-supply
> > +  - pvcc2-supply
> > +  - avcc-supply
> > +  - anvdd-supply
> > +  - apvdd-supply
> > +  - ports
> > +
> > +additionalProperties: false
> > +
> > +examples:
> > +  - |
> > +    /* single-link LVDS input */
> > +    #include <dt-bindings/gpio/gpio.h>
> > +
> > +    i2c {
> > +        #address-cells = <1>;
> > +        #size-cells = <0>;
> > +
> > +        hdmi@4c {
> > +            compatible = "ite,it6263";
> > +            reg = <0x4c>;
> > +            reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
> > +            ivdd-supply = <&reg_buck5>;
> > +            ovdd-supply = <&reg_vext_3v3>;
> > +            txavcc18-supply = <&reg_buck5>;
> > +            txavcc33-supply = <&reg_vext_3v3>;
> > +            pvcc1-supply = <&reg_buck5>;
> > +            pvcc2-supply = <&reg_buck5>;
> > +            avcc-supply = <&reg_vext_3v3>;
> > +            anvdd-supply = <&reg_buck5>;
> > +            apvdd-supply = <&reg_buck5>;
> > +
> > +            ports {
> > +                #address-cells = <1>;
> > +                #size-cells = <0>;
> > +
> > +                port@0 {
> > +                    reg = <0>;
> > +
> > +                    it6263_lvds_link1: endpoint {
> > +                        remote-endpoint = <&ldb_lvds_ch0>;
> > +                    };
> > +                };
> > +
> > +                port@2 {
> > +                    reg = <2>;
> > +
> > +                    it6263_out: endpoint {
> > +                        remote-endpoint = <&hdmi_in>;
> > +                    };
> > +                };
> > +            };
> > +        };
> > +    };
> > +
> > +  - |
> > +    /* dual-link LVDS input */
> > +    #include <dt-bindings/gpio/gpio.h>
> > +
> > +    i2c {
> > +        #address-cells = <1>;
> > +        #size-cells = <0>;
> > +
> > +        hdmi@4c {
> > +            compatible = "ite,it6263";
> > +            reg = <0x4c>;
> > +            reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
> > +            ivdd-supply = <&reg_buck5>;
> > +            ovdd-supply = <&reg_vext_3v3>;
> > +            txavcc18-supply = <&reg_buck5>;
> > +            txavcc33-supply = <&reg_vext_3v3>;
> > +            pvcc1-supply = <&reg_buck5>;
> > +            pvcc2-supply = <&reg_buck5>;
> > +            avcc-supply = <&reg_vext_3v3>;
> > +            anvdd-supply = <&reg_buck5>;
> > +            apvdd-supply = <&reg_buck5>;
> > +
> > +            ports {
> > +                #address-cells = <1>;
> > +                #size-cells = <0>;
> > +
> > +                port@0 {
> > +                    reg = <0>;
> > +                    dual-lvds-odd-pixels;
> > +
> > +                    it6263_lvds_link1_dual: endpoint {
> > +                        remote-endpoint = <&ldb_lvds_ch0>;
> > +                    };
> > +                };
> > +
> > +                port@1 {
> > +                    reg = <1>;
> > +                    dual-lvds-even-pixels;
> > +
> > +                    it6263_lvds_link2_dual: endpoint {
> > +                        remote-endpoint = <&ldb_lvds_ch1>;
> > +                    };
> > +                };
> > +
> > +                port@2 {
> > +                    reg = <2>;
> > +
> > +                    it6263_out_dual: endpoint {
> > +                        remote-endpoint = <&hdmi_in>;
> > +                    };
> > +                };
> > +            };
> > +        };
> > +    };
> > --
> > 2.34.1
> >


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

* Re: [PATCH 5/8] dt-bindings: display: bridge: Add ITE IT6263 LVDS to HDMI converter
  2024-09-30  5:29 ` [PATCH 5/8] dt-bindings: display: bridge: Add ITE IT6263 LVDS to HDMI converter Liu Ying
  2024-09-30  9:04   ` Biju Das
@ 2024-10-02  0:02   ` Rob Herring
  2024-10-09  7:00     ` Liu Ying
  1 sibling, 1 reply; 38+ messages in thread
From: Rob Herring @ 2024-10-02  0:02 UTC (permalink / raw)
  To: Liu Ying
  Cc: dri-devel, devicetree, linux-kernel, imx, linux-arm-kernel,
	andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart, jonas,
	jernej.skrabec, maarten.lankhorst, mripard, tzimmermann, airlied,
	simona, krzk+dt, conor+dt, shawnguo, s.hauer, kernel, festevam,
	catalin.marinas, will, quic_bjorande, geert+renesas,
	dmitry.baryshkov, arnd, nfraprado, o.rempel, y.moog

On Mon, Sep 30, 2024 at 01:29:00PM +0800, Liu Ying wrote:
> Document ITE IT6263 LVDS to HDMI converter.
> 
> Product link:
> https://www.ite.com.tw/en/product/cate1/IT6263
> 
> Signed-off-by: Liu Ying <victor.liu@nxp.com>
> ---
>  .../bindings/display/bridge/ite,it6263.yaml   | 310 ++++++++++++++++++
>  1 file changed, 310 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml
> 
> diff --git a/Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml b/Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml
> new file mode 100644
> index 000000000000..97fb81e5bc4a
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml
> @@ -0,0 +1,310 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/display/bridge/ite,it6263.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: ITE IT6263 LVDS to HDMI converter
> +
> +maintainers:
> +  - Liu Ying <victor.liu@nxp.com>
> +
> +description: |
> +  The IT6263 is a high-performance single-chip De-SSC(De-Spread Spectrum) LVDS
> +  to HDMI converter.  Combined with LVDS receiver and HDMI 1.4a transmitter,
> +  the IT6263 supports LVDS input and HDMI 1.4 output by conversion function.
> +  The built-in LVDS receiver can support single-link and dual-link LVDS inputs,
> +  and the built-in HDMI transmitter is fully compliant with HDMI 1.4a/3D, HDCP
> +  1.2 and backward compatible with DVI 1.0 specification.
> +
> +  The IT6263 also encodes and transmits up to 8 channels of I2S digital audio,
> +  with sampling rate up to 192KHz and sample size up to 24 bits. In addition,
> +  an S/PDIF input port takes in compressed audio of up to 192KHz frame rate.
> +
> +  The newly supported High-Bit Rate(HBR) audio by HDMI specifications v1.3 is
> +  provided by the IT6263 in two interfaces: the four I2S input ports or the
> +  S/PDIF input port.  With both interfaces the highest possible HBR frame rate
> +  is supported at up to 768KHz.
> +
> +properties:
> +  compatible:
> +    const: ite,it6263
> +
> +  reg:
> +    maxItems: 1
> +
> +  clocks:
> +    maxItems: 1
> +    description: audio master clock
> +
> +  clock-names:
> +    const: mclk
> +
> +  reset-gpios:
> +    maxItems: 1
> +
> +  ivdd-supply:
> +    description: 1.8V digital logic power
> +
> +  ovdd-supply:
> +    description: 3.3V I/O pin power
> +
> +  txavcc18-supply:
> +    description: 1.8V HDMI analog frontend power
> +
> +  txavcc33-supply:
> +    description: 3.3V HDMI analog frontend power
> +
> +  pvcc1-supply:
> +    description: 1.8V HDMI frontend core PLL power
> +
> +  pvcc2-supply:
> +    description: 1.8V HDMI frontend filter PLL power
> +
> +  avcc-supply:
> +    description: 3.3V LVDS frontend power
> +
> +  anvdd-supply:
> +    description: 1.8V LVDS frontend analog power
> +
> +  apvdd-supply:
> +    description: 1.8V LVDS frontend PLL power
> +
> +  "#sound-dai-cells":
> +    const: 0
> +
> +  ite,i2s-audio-fifo-sources:
> +    $ref: /schemas/types.yaml#/definitions/uint32-array
> +    minItems: 1
> +    maxItems: 4
> +    items:
> +      enum: [0, 1, 2, 3]
> +    description:
> +      Each array element indicates the pin number of an I2S serial data input
> +      line which is connected to an audio FIFO, from audio FIFO0 to FIFO3.
> +
> +  ite,rl-channel-swap-audio-sources:
> +    $ref: /schemas/types.yaml#/definitions/uint32-array
> +    minItems: 1
> +    maxItems: 4
> +    uniqueItems: true
> +    items:
> +      enum: [0, 1, 2, 3]
> +    description:
> +      Each array element indicates an audio source whose right channel and left
> +      channel are swapped by this converter. For I2S, the element is the pin
> +      number of an I2S serial data input line. For S/PDIF, the element is always
> +      0.
> +
> +  ports:
> +    $ref: /schemas/graph.yaml#/properties/ports

Test your bindings. You need 'additionalProperties: false' here. Though 
I can't remember if that can 'see' properties under the oneOf. So it may 
have to be unevaluatedProperties instead.

> +
> +    oneOf:

I think you can get rid of this. If port@1 requires the dual link 
properties and then properties on port@0, then the only way you can have 
a single link is removing port@1 from the DT. 

> +      - properties:
> +          port@0:
> +            $ref: /schemas/graph.yaml#/properties/port
> +            description: the first LVDS input link
> +
> +          port@1: false
> +
> +          port@2:
> +            $ref: /schemas/graph.yaml#/properties/port
> +            description: video port for the HDMI output
> +
> +          port@3:
> +            $ref: /schemas/graph.yaml#/properties/port
> +            description: sound input port
> +
> +        required:
> +          - port@0
> +          - port@2
> +
> +      - properties:
> +          port@0:
> +            $ref: /schemas/graph.yaml#/$defs/port-base
> +            unevaluatedProperties: false
> +            description: the first LVDS input link
> +
> +            properties:
> +              dual-lvds-odd-pixels:
> +                type: boolean
> +                description: the first sink port for odd pixels
> +
> +              dual-lvds-even-pixels:
> +                type: boolean
> +                description: the first sink port for even pixels
> +
> +            oneOf:
> +              - required: [dual-lvds-odd-pixels]
> +              - required: [dual-lvds-even-pixels]
> +
> +          port@1:
> +            $ref: /schemas/graph.yaml#/$defs/port-base
> +            unevaluatedProperties: false
> +            description: the second LVDS input link
> +
> +            properties:
> +              dual-lvds-even-pixels:
> +                type: boolean
> +                description: the second sink port for even pixels
> +
> +              dual-lvds-odd-pixels:
> +                type: boolean
> +                description: the second sink port for odd pixels
> +
> +            oneOf:
> +              - required: [dual-lvds-even-pixels]
> +              - required: [dual-lvds-odd-pixels]
> +
> +          port@2:
> +            $ref: /schemas/graph.yaml#/properties/port
> +            description: video port for the HDMI output
> +
> +          port@3:
> +            $ref: /schemas/graph.yaml#/properties/port
> +            description: sound input port
> +
> +        required:
> +          - port@0
> +          - port@1
> +          - port@2
> +
> +        allOf:
> +          - if:
> +              properties:
> +                port@0:
> +                  required:
> +                    - dual-lvds-odd-pixels
> +            then:
> +              properties:
> +                port@1:
> +                  properties:
> +                    dual-lvds-odd-pixels: false
> +
> +          - if:
> +              properties:
> +                port@0:
> +                  required:
> +                    - dual-lvds-even-pixels
> +            then:
> +              properties:
> +                port@1:
> +                  properties:
> +                    dual-lvds-even-pixels: false
> +
> +required:
> +  - compatible
> +  - reg
> +  - ivdd-supply
> +  - ovdd-supply
> +  - txavcc18-supply
> +  - txavcc33-supply
> +  - pvcc1-supply
> +  - pvcc2-supply
> +  - avcc-supply
> +  - anvdd-supply
> +  - apvdd-supply
> +  - ports
> +
> +additionalProperties: false
> +

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

* RE: [PATCH 6/8] drm/bridge: Add ITE IT6263 LVDS to HDMI converter
  2024-09-30  5:29 ` [PATCH 6/8] drm/bridge: " Liu Ying
  2024-09-30  7:11   ` Maxime Ripard
  2024-09-30  9:16   ` Biju Das
@ 2024-10-02 10:19   ` Biju Das
  2 siblings, 0 replies; 38+ messages in thread
From: Biju Das @ 2024-10-02 10:19 UTC (permalink / raw)
  To: Liu Ying, dri-devel@lists.freedesktop.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linux-arm-kernel@lists.infradead.org
  Cc: andrzej.hajda@intel.com, neil.armstrong@linaro.org,
	rfoss@kernel.org, laurent.pinchart, jonas@kwiboo.se,
	jernej.skrabec@gmail.com, maarten.lankhorst@linux.intel.com,
	mripard@kernel.org, tzimmermann@suse.de, airlied@gmail.com,
	simona@ffwll.ch, robh@kernel.org, krzk+dt@kernel.org,
	conor+dt@kernel.org, shawnguo@kernel.org, s.hauer@pengutronix.de,
	kernel@pengutronix.de, festevam@gmail.com,
	catalin.marinas@arm.com, will@kernel.org,
	quic_bjorande@quicinc.com, geert+renesas@glider.be,
	dmitry.baryshkov@linaro.org, arnd@arndb.de,
	nfraprado@collabora.com, o.rempel@pengutronix.de,
	y.moog@phytec.de

Hi Liu Ying,

> -----Original Message-----
> From: linux-arm-kernel <linux-arm-kernel-bounces@lists.infradead.org> On Behalf Of Liu Ying
> Sent: Monday, September 30, 2024 6:29 AM
> Subject: [PATCH 6/8] drm/bridge: Add ITE IT6263 LVDS to HDMI converter
> 
> Add basic HDMI video output support. Currently, only RGB888 output pixel format is supported.  At the
> LVDS input side, the driver supports single LVDS link and dual LVDS links with "jeida-24" LVDS
> mapping.
> 
> Product link:
> https://www.ite.com.tw/en/product/cate1/IT6263
> 
> Signed-off-by: Liu Ying <victor.liu@nxp.com>

I have tested this patch on Renesas RZ/G3E SMARC EVK in dual LVDS mode
with JEDAI mapping. Please add me in loop when you send next version.
So, that I can test and provide feedback. 

Tested-by: Biju Das <biju.das.jz@bp.renesas.com>

Cheers,
Biju

> ---
>  drivers/gpu/drm/bridge/Kconfig      |   8 +
>  drivers/gpu/drm/bridge/Makefile     |   1 +
>  drivers/gpu/drm/bridge/ite-it6263.c | 829 ++++++++++++++++++++++++++++
>  3 files changed, 838 insertions(+)
>  create mode 100644 drivers/gpu/drm/bridge/ite-it6263.c
> 
> diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index
> 3eb955333c80..93f99682a090 100644
> --- a/drivers/gpu/drm/bridge/Kconfig
> +++ b/drivers/gpu/drm/bridge/Kconfig
> @@ -90,6 +90,14 @@ config DRM_FSL_LDB
>  	help
>  	  Support for i.MX8MP DPI-to-LVDS on-SoC encoder.
> 
> +config DRM_ITE_IT6263
> +	tristate "ITE IT6263 LVDS/HDMI bridge"
> +	depends on OF
> +	select DRM_KMS_HELPER
> +	select REGMAP_I2C
> +	help
> +	  ITE IT6263 LVDS to HDMI bridge chip driver.
> +
>  config DRM_ITE_IT6505
>  	tristate "ITE IT6505 DisplayPort bridge"
>  	depends on OF
> diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index
> 7df87b582dca..f3776dd473fd 100644
> --- a/drivers/gpu/drm/bridge/Makefile
> +++ b/drivers/gpu/drm/bridge/Makefile
> @@ -6,6 +6,7 @@ obj-$(CONFIG_DRM_CHRONTEL_CH7033) += chrontel-ch7033.o
>  obj-$(CONFIG_DRM_CROS_EC_ANX7688) += cros-ec-anx7688.o
>  obj-$(CONFIG_DRM_DISPLAY_CONNECTOR) += display-connector.o
>  obj-$(CONFIG_DRM_FSL_LDB) += fsl-ldb.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
>  obj-$(CONFIG_DRM_LONTIUM_LT9211) += lontium-lt9211.o diff --git a/drivers/gpu/drm/bridge/ite-it6263.c
> b/drivers/gpu/drm/bridge/ite-it6263.c
> new file mode 100644
> index 000000000000..886588497bc1
> --- /dev/null
> +++ b/drivers/gpu/drm/bridge/ite-it6263.c
> @@ -0,0 +1,829 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright 2024 NXP
> + */
> +
> +#include <linux/bitfield.h>
> +#include <linux/bits.h>
> +#include <linux/delay.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/i2c.h>
> +#include <linux/media-bus-format.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/regmap.h>
> +#include <linux/regulator/consumer.h>
> +
> +#include <drm/drm_atomic.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_atomic_state_helper.h> #include <drm/drm_bridge.h>
> +#include <drm/drm_connector.h> #include <drm/drm_crtc.h> #include
> +<drm/drm_edid.h> #include <drm/drm_of.h> #include
> +<drm/drm_probe_helper.h>
> +
> +/*
> +-----------------------------------------------------------------------
> +------
> + * LVDS registers
> + */
> +
> +/* LVDS software reset registers */
> +#define LVDS_REG_05			0x05
> +#define  REG_SOFT_P_RST			BIT(1)
> +
> +/* LVDS system configuration registers */
> +/* 0x0b */
> +#define LVDS_REG_0B			0x0b
> +#define  REG_SSC_PCLK_RF		BIT(0)
> +#define  REG_LVDS_IN_SWAP		BIT(1)
> +
> +/* LVDS test pattern gen control registers */
> +/* 0x2c */
> +#define LVDS_REG_2C			0x2c
> +#define  REG_COL_DEP			GENMASK(1, 0)
> +#define  BIT8				FIELD_PREP(REG_COL_DEP, 2)
> +#define  OUT_MAP			BIT(4)
> +#define  JEIDA				0
> +#define  REG_DESSC_ENB			BIT(6)
> +#define  DMODE				BIT(7)
> +#define  DISO				BIT(7)
> +#define  SISO				0
> +
> +#define LVDS_REG_3C			0x3c
> +#define LVDS_REG_3F			0x3f
> +#define LVDS_REG_47			0x47
> +#define LVDS_REG_48			0x48
> +#define LVDS_REG_4F			0x4f
> +#define LVDS_REG_52			0x52
> +
> +/*
> +-----------------------------------------------------------------------
> +------
> + * HDMI registers are separated into three banks:
> + * 1) HDMI register common bank: 0x00 ~ 0x2f  */
> +
> +/* HDMI genernal registers */
> +#define HDMI_REG_SW_RST			0x04
> +#define  SOFTREF_RST			BIT(5)
> +#define  SOFTA_RST			BIT(4)
> +#define  SOFTV_RST			BIT(3)
> +#define  AUD_RST			BIT(2)
> +#define  HDCP_RST			BIT(0)
> +#define  HDMI_RST_ALL			(SOFTREF_RST | SOFTA_RST | SOFTV_RST | \
> +					 AUD_RST | HDCP_RST)
> +
> +#define HDMI_REG_SYS_STATUS		0x0e
> +#define  HPDETECT			BIT(6)
> +#define  TXVIDSTABLE			BIT(4)
> +
> +#define HDMI_REG_BANK_CTRL		0x0f
> +#define  REG_BANK_SEL			BIT(0)
> +
> +/* HDMI System DDC control registers */
> +#define HDMI_REG_DDC_MASTER_CTRL	0x10
> +#define  MASTER_SEL_HOST		BIT(0)
> +
> +#define HDMI_REG_DDC_HEADER		0x11
> +
> +#define HDMI_REG_DDC_REQOFF		0x12
> +#define HDMI_REG_DDC_REQCOUNT		0x13
> +#define HDMI_REG_DDC_EDIDSEG		0x14
> +
> +#define HDMI_REG_DDC_CMD		0x15
> +#define  DDC_CMD_EDID_READ		0x3
> +#define  DDC_CMD_FIFO_CLR		0x9
> +
> +#define HDMI_REG_DDC_STATUS		0x16
> +#define  DDC_DONE			BIT(7)
> +#define  DDC_NOACK			BIT(5)
> +#define  DDC_WAITBUS			BIT(4)
> +#define  DDC_ARBILOSE			BIT(3)
> +#define  DDC_ERROR			(DDC_NOACK | DDC_WAITBUS | DDC_ARBILOSE)
> +
> +#define HDMI_DDC_FIFO_BYTES		32
> +#define HDMI_REG_DDC_READFIFO		0x17
> +#define HDMI_REG_LVDS_PORT		0x1d /* LVDS input control I2C addr */
> +#define HDMI_REG_LVDS_PORT_EN		0x1e
> +#define LVDS_INPUT_CTRL_I2C_ADDR	0x33
> +
> +/*
> +-----------------------------------------------------------------------
> +------
> + * 2) HDMI register bank0: 0x30 ~ 0xff
> + */
> +
> +/* HDMI AFE registers */
> +#define HDMI_REG_AFE_DRV_CTRL		0x61
> +#define  AFE_DRV_PWD			BIT(5)
> +#define  AFE_DRV_RST			BIT(4)
> +
> +#define HDMI_REG_AFE_XP_CTRL		0x62
> +#define  AFE_XP_GAINBIT			BIT(7)
> +#define  AFE_XP_ER0			BIT(4)
> +#define  AFE_XP_RESETB			BIT(3)
> +
> +#define HDMI_REG_AFE_ISW_CTRL		0x63
> +
> +#define HDMI_REG_AFE_IP_CTRL		0x64
> +#define  AFE_IP_GAINBIT			BIT(7)
> +#define  AFE_IP_ER0			BIT(3)
> +#define  AFE_IP_RESETB			BIT(2)
> +
> +/* HDMI input data format registers */
> +#define HDMI_REG_INPUT_MODE		0x70
> +#define  IN_RGB				0x00
> +
> +/* HDMI general control registers */
> +#define HDMI_REG_HDMI_MODE		0xc0
> +#define  TX_HDMI_MODE			BIT(0)
> +
> +#define HDMI_REG_GCP			0xc1
> +#define  AVMUTE				BIT(0)
> +#define  HDMI_COLOR_DEPTH		GENMASK(6, 4)
> +#define  HDMI_COLOR_DEPTH_24		FIELD_PREP(HDMI_COLOR_DEPTH, 4)
> +
> +#define HDMI_REG_PKT_GENERAL_CTRL	0xc6
> +#define  ENABLE_PKT			BIT(0)
> +#define  REPEAT_PKT			BIT(1)
> +
> +/*
> +-----------------------------------------------------------------------
> +------
> + * 3) HDMI register bank1: 0x130 ~ 0x1ff (HDMI packet registers)  */
> +
> +/* AVI packet registers */
> +#define HDMI_REG_AVI_DB1		0x158
> +#define  AVI_DB1_COLOR_SPACE		GENMASK(6, 5)
> +#define  AVI_COLOR_SPACE_RGB		FIELD_PREP(AVI_DB1_COLOR_SPACE, 0)
> +
> +#define MAX_PIXEL_CLOCK_KHZ		150000
> +#define HIGH_PIXEL_CLOCK_KHZ		80000
> +
> +struct it6263 {
> +	struct device *dev;
> +	struct i2c_client *hdmi_i2c;
> +	struct i2c_client *lvds_i2c;
> +	struct regmap *hdmi_regmap;
> +	struct regmap *lvds_regmap;
> +	struct drm_bridge bridge;
> +	struct drm_bridge *next_bridge;
> +	struct drm_connector connector;
> +	struct gpio_desc *reset_gpio;
> +	bool lvds_dual_link;
> +	bool lvds_link12_swap;
> +};
> +
> +static inline struct it6263 *bridge_to_it6263(struct drm_bridge
> +*bridge) {
> +	return container_of(bridge, struct it6263, bridge); }
> +
> +static inline struct it6263 *connector_to_it6263(struct drm_connector
> +*conn) {
> +	return container_of(conn, struct it6263, connector); }
> +
> +static bool it6263_hdmi_writeable_reg(struct device *dev, unsigned int
> +reg) {
> +	switch (reg) {
> +	case HDMI_REG_SW_RST:
> +	case HDMI_REG_BANK_CTRL:
> +	case HDMI_REG_DDC_MASTER_CTRL:
> +	case HDMI_REG_DDC_HEADER:
> +	case HDMI_REG_DDC_REQOFF:
> +	case HDMI_REG_DDC_REQCOUNT:
> +	case HDMI_REG_DDC_EDIDSEG:
> +	case HDMI_REG_DDC_CMD:
> +	case HDMI_REG_LVDS_PORT:
> +	case HDMI_REG_LVDS_PORT_EN:
> +	case HDMI_REG_AFE_DRV_CTRL:
> +	case HDMI_REG_AFE_XP_CTRL:
> +	case HDMI_REG_AFE_ISW_CTRL:
> +	case HDMI_REG_AFE_IP_CTRL:
> +	case HDMI_REG_INPUT_MODE:
> +	case HDMI_REG_HDMI_MODE:
> +	case HDMI_REG_GCP:
> +	case HDMI_REG_PKT_GENERAL_CTRL:
> +	case HDMI_REG_AVI_DB1:
> +		return true;
> +	default:
> +		return false;
> +	}
> +}
> +
> +static bool it6263_hdmi_readable_reg(struct device *dev, unsigned int
> +reg) {
> +	if (it6263_hdmi_writeable_reg(dev, reg))
> +		return true;
> +
> +	switch (reg) {
> +	case HDMI_REG_SYS_STATUS:
> +	case HDMI_REG_DDC_STATUS:
> +	case HDMI_REG_DDC_READFIFO:
> +		return true;
> +	default:
> +		return false;
> +	}
> +}
> +
> +static bool it6263_hdmi_volatile_reg(struct device *dev, unsigned int
> +reg) {
> +	switch (reg) {
> +	case HDMI_REG_SW_RST:
> +	case HDMI_REG_SYS_STATUS:
> +	case HDMI_REG_DDC_STATUS:
> +	case HDMI_REG_DDC_READFIFO:
> +		return true;
> +	default:
> +		return false;
> +	}
> +}
> +
> +static const struct regmap_range_cfg it6263_hdmi_range_cfg = {
> +	.range_min = 0x00,
> +	.range_max = HDMI_REG_AVI_DB1,
> +	.selector_reg = HDMI_REG_BANK_CTRL,
> +	.selector_mask = REG_BANK_SEL,
> +	.selector_shift = 0,
> +	.window_start = 0x00,
> +	.window_len = 0x100,
> +};
> +
> +static const struct regmap_config it6263_hdmi_regmap_config = {
> +	.name = "it6263-hdmi",
> +	.reg_bits = 8,
> +	.val_bits = 8,
> +	.writeable_reg = it6263_hdmi_writeable_reg,
> +	.readable_reg = it6263_hdmi_readable_reg,
> +	.volatile_reg = it6263_hdmi_volatile_reg,
> +	.max_register = HDMI_REG_AVI_DB1,
> +	.ranges = &it6263_hdmi_range_cfg,
> +	.num_ranges = 1,
> +	.cache_type = REGCACHE_MAPLE,
> +};
> +
> +static bool it6263_lvds_writeable_reg(struct device *dev, unsigned int
> +reg) {
> +	switch (reg) {
> +	case LVDS_REG_05:
> +	case LVDS_REG_0B:
> +	case LVDS_REG_2C:
> +	case LVDS_REG_3C:
> +	case LVDS_REG_3F:
> +	case LVDS_REG_47:
> +	case LVDS_REG_48:
> +	case LVDS_REG_4F:
> +	case LVDS_REG_52:
> +		return true;
> +	default:
> +		return false;
> +	}
> +}
> +
> +static bool it6263_lvds_readable_reg(struct device *dev, unsigned int
> +reg) {
> +	return it6263_lvds_writeable_reg(dev, reg); }
> +
> +static bool it6263_lvds_volatile_reg(struct device *dev, unsigned int
> +reg) {
> +	return reg == LVDS_REG_05;
> +}
> +
> +static const struct regmap_config it6263_lvds_regmap_config = {
> +	.name = "it6263-lvds",
> +	.reg_bits = 8,
> +	.val_bits = 8,
> +	.writeable_reg = it6263_lvds_writeable_reg,
> +	.readable_reg = it6263_lvds_readable_reg,
> +	.volatile_reg = it6263_lvds_volatile_reg,
> +	.max_register = LVDS_REG_52,
> +	.cache_type = REGCACHE_MAPLE,
> +};
> +
> +static const char * const it6263_supplies[] = {
> +	"ivdd", "ovdd", "txavcc18", "txavcc33", "pvcc1", "pvcc2",
> +	"avcc", "anvdd", "apvdd"
> +};
> +
> +static int it6263_parse_dt(struct it6263 *it) {
> +	struct device *dev = it->dev;
> +	struct device_node *port0, *port1;
> +	int ret = 0;
> +
> +	it->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 2, 0);
> +	if (IS_ERR(it->next_bridge))
> +		return dev_err_probe(dev, PTR_ERR(it->next_bridge),
> +				     "failed to get next bridge\n");
> +
> +	port0 = of_graph_get_port_by_id(dev->of_node, 0);
> +	port1 = of_graph_get_port_by_id(dev->of_node, 1);
> +	if (port0 && port1) {
> +		if (of_property_read_bool(port0, "dual-lvds-even-pixels") &&
> +		    of_property_read_bool(port1, "dual-lvds-odd-pixels")) {
> +			it->lvds_dual_link = true;
> +			it->lvds_link12_swap = true;
> +		} else if (of_property_read_bool(port0, "dual-lvds-odd-pixels") &&
> +			   of_property_read_bool(port1, "dual-lvds-even-pixels")) {
> +			it->lvds_dual_link = true;
> +		}
> +
> +		if (!it->lvds_dual_link) {
> +			dev_err(dev,
> +				"failed to get LVDS dual link pixel order\n");
> +			ret = -EINVAL;
> +		}
> +	} else if (port1) {
> +		ret = -EINVAL;
> +		dev_err(dev, "single input LVDS port1 is not supported\n");
> +	} else if (!port0) {
> +		ret = -EINVAL;
> +		dev_err(dev, "no input LVDS port\n");
> +	}
> +
> +	of_node_put(port0);
> +	of_node_put(port1);
> +
> +	return ret;
> +}
> +
> +static inline void it6263_reset(struct it6263 *it) {
> +	if (!it->reset_gpio)
> +		return;
> +
> +	gpiod_set_value_cansleep(it->reset_gpio, 0);
> +	fsleep(1000);
> +	gpiod_set_value_cansleep(it->reset_gpio, 1);
> +	/* The chip maker says the low pulse should be at least 40ms. */
> +	fsleep(40000);
> +	gpiod_set_value_cansleep(it->reset_gpio, 0);
> +	/* addtional time to wait the high voltage to be stable */
> +	fsleep(5000);
> +}
> +
> +static inline int it6263_lvds_set_i2c_addr(struct it6263 *it) {
> +	int ret;
> +
> +	ret = regmap_write(it->hdmi_regmap, HDMI_REG_LVDS_PORT,
> +			   LVDS_INPUT_CTRL_I2C_ADDR << 1);
> +	if (ret)
> +		return ret;
> +
> +	return regmap_write(it->hdmi_regmap, HDMI_REG_LVDS_PORT_EN, BIT(0)); }
> +
> +static inline void it6263_lvds_reset(struct it6263 *it) {
> +	/* AFE PLL reset */
> +	regmap_write_bits(it->lvds_regmap, LVDS_REG_3C, BIT(0), 0x0);
> +	fsleep(1000);
> +	regmap_write_bits(it->lvds_regmap, LVDS_REG_3C, BIT(0), BIT(0));
> +
> +	/* software pixel clock domain reset */
> +	regmap_write_bits(it->lvds_regmap, LVDS_REG_05, REG_SOFT_P_RST,
> +			  REG_SOFT_P_RST);
> +	fsleep(1000);
> +	regmap_write_bits(it->lvds_regmap, LVDS_REG_05, REG_SOFT_P_RST, 0x0);
> +	fsleep(10000);
> +}
> +
> +static inline void it6263_lvds_set_interface(struct it6263 *it) {
> +	/* color depth */
> +	regmap_write_bits(it->lvds_regmap, LVDS_REG_2C, REG_COL_DEP, BIT8);
> +	/* output mapping */
> +	regmap_write_bits(it->lvds_regmap, LVDS_REG_2C, OUT_MAP, JEIDA);
> +
> +	if (it->lvds_dual_link) {
> +		regmap_write_bits(it->lvds_regmap, LVDS_REG_2C, DMODE, DISO);
> +		regmap_write_bits(it->lvds_regmap, LVDS_REG_52, BIT(1), BIT(1));
> +	} else {
> +		regmap_write_bits(it->lvds_regmap, LVDS_REG_2C, DMODE, SISO);
> +		regmap_write_bits(it->lvds_regmap, LVDS_REG_52, BIT(1), 0);
> +	}
> +}
> +
> +static inline void it6263_lvds_set_afe(struct it6263 *it) {
> +	regmap_write(it->lvds_regmap, LVDS_REG_3C, 0xaa);
> +	regmap_write(it->lvds_regmap, LVDS_REG_3F, 0x02);
> +	regmap_write(it->lvds_regmap, LVDS_REG_47, 0xaa);
> +	regmap_write(it->lvds_regmap, LVDS_REG_48, 0x02);
> +	regmap_write(it->lvds_regmap, LVDS_REG_4F, 0x11);
> +
> +	regmap_write_bits(it->lvds_regmap, LVDS_REG_0B, REG_SSC_PCLK_RF,
> +			  REG_SSC_PCLK_RF);
> +	regmap_write_bits(it->lvds_regmap, LVDS_REG_3C, 0x07, 0);
> +	regmap_write_bits(it->lvds_regmap, LVDS_REG_2C, REG_DESSC_ENB,
> +			  REG_DESSC_ENB);
> +}
> +
> +static inline void it6263_lvds_sys_cfg(struct it6263 *it) {
> +	regmap_write_bits(it->lvds_regmap, LVDS_REG_0B, REG_LVDS_IN_SWAP,
> +			  it->lvds_link12_swap ? REG_LVDS_IN_SWAP : 0); }
> +
> +static inline void it6263_lvds_config(struct it6263 *it) {
> +	it6263_lvds_reset(it);
> +	it6263_lvds_set_interface(it);
> +	it6263_lvds_set_afe(it);
> +	it6263_lvds_sys_cfg(it);
> +}
> +
> +static inline void it6263_hdmi_config(struct it6263 *it) {
> +	regmap_write(it->hdmi_regmap, HDMI_REG_SW_RST, HDMI_RST_ALL);
> +	regmap_write(it->hdmi_regmap, HDMI_REG_INPUT_MODE, IN_RGB);
> +	regmap_write_bits(it->hdmi_regmap, HDMI_REG_GCP, HDMI_COLOR_DEPTH,
> +			  HDMI_COLOR_DEPTH_24);
> +	regmap_write_bits(it->hdmi_regmap, HDMI_REG_AVI_DB1,
> +			  AVI_DB1_COLOR_SPACE, AVI_COLOR_SPACE_RGB); }
> +
> +static enum drm_connector_status it6263_detect(struct it6263 *it) {
> +	unsigned int val;
> +
> +	regmap_read(it->hdmi_regmap, HDMI_REG_SYS_STATUS, &val);
> +	if (val & HPDETECT)
> +		return connector_status_connected;
> +	else
> +		return connector_status_disconnected; }
> +
> +static enum drm_connector_status
> +it6263_connector_detect(struct drm_connector *connector, bool force) {
> +	struct it6263 *it = connector_to_it6263(connector);
> +
> +	return it6263_detect(it);
> +}
> +
> +static const struct drm_connector_funcs it6263_connector_funcs = {
> +	.detect = it6263_connector_detect,
> +	.fill_modes = drm_helper_probe_single_connector_modes,
> +	.destroy = drm_connector_cleanup,
> +	.reset = drm_atomic_helper_connector_reset,
> +	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> +	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> +};
> +
> +static int it6263_read_edid(void *data, u8 *buf, unsigned int block,
> +size_t len) {
> +	struct it6263 *it = data;
> +	struct regmap *regmap = it->hdmi_regmap;
> +	unsigned int start = (block % 2) * EDID_LENGTH;
> +	unsigned int segment = block >> 1;
> +	unsigned int count, val;
> +	int ret;
> +
> +	regmap_write(regmap, HDMI_REG_DDC_MASTER_CTRL, MASTER_SEL_HOST);
> +	regmap_write(regmap, HDMI_REG_DDC_HEADER, DDC_ADDR << 1);
> +	regmap_write(regmap, HDMI_REG_DDC_EDIDSEG, segment);
> +
> +	while (len) {
> +		/* clear DDC FIFO */
> +		regmap_write(regmap, HDMI_REG_DDC_CMD, DDC_CMD_FIFO_CLR);
> +
> +		ret = regmap_read_poll_timeout(regmap, HDMI_REG_DDC_STATUS,
> +					       val, val & DDC_DONE,
> +					       2000, 10000);
> +		if (ret) {
> +			dev_err(it->dev, "failed to clear DDC FIFO:%d\n", ret);
> +			return ret;
> +		}
> +
> +		count = len > HDMI_DDC_FIFO_BYTES ? HDMI_DDC_FIFO_BYTES : len;
> +
> +		/* fire the read command */
> +		regmap_write(regmap, HDMI_REG_DDC_REQOFF, start);
> +		regmap_write(regmap, HDMI_REG_DDC_REQCOUNT, count);
> +		regmap_write(regmap, HDMI_REG_DDC_CMD, DDC_CMD_EDID_READ);
> +
> +		start += count;
> +		len -= count;
> +
> +		ret = regmap_read_poll_timeout(regmap, HDMI_REG_DDC_STATUS, val,
> +					       val & (DDC_DONE | DDC_ERROR),
> +					       20000, 250000);
> +		if (ret && !(val & DDC_ERROR)) {
> +			dev_err(it->dev, "failed to read EDID:%d\n", ret);
> +			return ret;
> +		}
> +
> +		if (val & DDC_ERROR) {
> +			dev_err(it->dev, "DDC error\n");
> +			return -EIO;
> +		}
> +
> +		/* cache to buffer */
> +		for (; count > 0; count--) {
> +			regmap_read(regmap, HDMI_REG_DDC_READFIFO, &val);
> +			*(buf++) = val;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int it6263_connector_get_modes(struct drm_connector *connector)
> +{
> +	struct it6263 *it = connector_to_it6263(connector);
> +	const struct drm_edid *drm_edid;
> +	int count;
> +
> +	drm_edid = drm_edid_read_custom(connector, it6263_read_edid, it);
> +
> +	drm_edid_connector_update(connector, drm_edid);
> +	count = drm_edid_connector_add_modes(connector);
> +
> +	drm_edid_free(drm_edid);
> +
> +	return count;
> +}
> +
> +static const struct drm_connector_helper_funcs it6263_connector_helper_funcs = {
> +	.get_modes = it6263_connector_get_modes, };
> +
> +static int it6263_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 *mode = &crtc_state->adjusted_mode;
> +
> +	return mode->clock > MAX_PIXEL_CLOCK_KHZ ? -EINVAL : 0; }
> +
> +static void
> +it6263_bridge_atomic_disable(struct drm_bridge *bridge,
> +			     struct drm_bridge_state *old_bridge_state) {
> +	struct it6263 *it = bridge_to_it6263(bridge);
> +
> +	regmap_write_bits(it->hdmi_regmap, HDMI_REG_GCP, AVMUTE, AVMUTE);
> +	regmap_write(it->hdmi_regmap, HDMI_REG_PKT_GENERAL_CTRL, 0);
> +	regmap_write(it->hdmi_regmap, HDMI_REG_AFE_DRV_CTRL,
> +		     AFE_DRV_RST | AFE_DRV_PWD);
> +}
> +
> +static void
> +it6263_bridge_atomic_enable(struct drm_bridge *bridge,
> +			    struct drm_bridge_state *old_bridge_state) {
> +	struct drm_atomic_state *state = old_bridge_state->base.state;
> +	struct it6263 *it = bridge_to_it6263(bridge);
> +	const struct drm_crtc_state *crtc_state;
> +	struct regmap *regmap = it->hdmi_regmap;
> +	const struct drm_display_mode *mode;
> +	struct drm_connector *connector;
> +	bool is_stable = false;
> +	struct drm_crtc *crtc;
> +	unsigned int val;
> +	bool pclk_high;
> +	int i, ret;
> +
> +	connector = drm_atomic_get_new_connector_for_encoder(state,
> +							     bridge->encoder);
> +	crtc = drm_atomic_get_new_connector_state(state, connector)->crtc;
> +	crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
> +	mode = &crtc_state->adjusted_mode;
> +
> +	regmap_write(regmap, HDMI_REG_HDMI_MODE, TX_HDMI_MODE);
> +
> +	/* HDMI AFE setup */
> +	pclk_high = mode->clock > HIGH_PIXEL_CLOCK_KHZ ? true : false;
> +	regmap_write(regmap, HDMI_REG_AFE_DRV_CTRL, AFE_DRV_RST);
> +	if (pclk_high)
> +		regmap_write(regmap, HDMI_REG_AFE_XP_CTRL,
> +			     AFE_XP_GAINBIT | AFE_XP_RESETB);
> +	else
> +		regmap_write(regmap, HDMI_REG_AFE_XP_CTRL,
> +			     AFE_XP_ER0 | AFE_XP_RESETB);
> +	regmap_write(regmap, HDMI_REG_AFE_ISW_CTRL, 0x10);
> +	if (pclk_high)
> +		regmap_write(regmap, HDMI_REG_AFE_IP_CTRL,
> +			     AFE_IP_GAINBIT | AFE_IP_RESETB);
> +	else
> +		regmap_write(regmap, HDMI_REG_AFE_IP_CTRL,
> +			     AFE_IP_ER0 | AFE_IP_RESETB);
> +
> +	/* HDMI software video reset */
> +	regmap_write_bits(regmap, HDMI_REG_SW_RST, SOFTV_RST, SOFTV_RST);
> +	fsleep(1000);
> +	regmap_write_bits(regmap, HDMI_REG_SW_RST, SOFTV_RST, 0);
> +
> +	/* reconfigure LVDS and retry several times in case video is instable */
> +	for (i = 0; i < 3; i++) {
> +		ret = regmap_read_poll_timeout(regmap, HDMI_REG_SYS_STATUS, val,
> +					       val & TXVIDSTABLE,
> +					       20000, 500000);
> +		if (!ret) {
> +			is_stable = true;
> +			break;
> +		}
> +
> +		it6263_lvds_config(it);
> +	}
> +
> +	if (!is_stable)
> +		dev_warn(it->dev, "failed to wait for video stable\n");
> +
> +	/* HDMI AFE reset release and power up */
> +	regmap_write(regmap, HDMI_REG_AFE_DRV_CTRL, 0);
> +
> +	regmap_write_bits(regmap, HDMI_REG_GCP, AVMUTE, 0);
> +
> +	regmap_write(regmap, HDMI_REG_PKT_GENERAL_CTRL, ENABLE_PKT |
> +REPEAT_PKT); }
> +
> +static enum drm_mode_status
> +it6263_bridge_mode_valid(struct drm_bridge *bridge,
> +			 const struct drm_display_info *info,
> +			 const struct drm_display_mode *mode) {
> +	return mode->clock > MAX_PIXEL_CLOCK_KHZ ? MODE_CLOCK_HIGH : MODE_OK;
> +}
> +
> +static int it6263_bridge_attach(struct drm_bridge *bridge,
> +				enum drm_bridge_attach_flags flags) {
> +	struct it6263 *it = bridge_to_it6263(bridge);
> +	int ret;
> +
> +	ret = drm_bridge_attach(bridge->encoder, it->next_bridge, bridge,
> +				flags | DRM_BRIDGE_ATTACH_NO_CONNECTOR);
> +	if (ret < 0)
> +		return ret;
> +
> +	if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
> +		return 0;
> +
> +	it->connector.polled = DRM_CONNECTOR_POLL_CONNECT |
> +			       DRM_CONNECTOR_POLL_DISCONNECT;
> +
> +	ret = drm_connector_init(bridge->dev, &it->connector,
> +				 &it6263_connector_funcs,
> +				 DRM_MODE_CONNECTOR_HDMIA);
> +	if (ret)
> +		return ret;
> +
> +	drm_connector_helper_add(&it->connector,
> +				 &it6263_connector_helper_funcs);
> +	drm_connector_attach_encoder(&it->connector, bridge->encoder);
> +
> +	return 0;
> +}
> +
> +static enum drm_connector_status it6263_bridge_detect(struct drm_bridge
> +*bridge) {
> +	struct it6263 *it = bridge_to_it6263(bridge);
> +
> +	return it6263_detect(it);
> +}
> +
> +static const struct drm_edid *
> +it6263_bridge_edid_read(struct drm_bridge *bridge,
> +			struct drm_connector *connector)
> +{
> +	struct it6263 *it = bridge_to_it6263(bridge);
> +
> +	return drm_edid_read_custom(connector, it6263_read_edid, it); }
> +
> +static u32 *
> +it6263_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
> +					struct drm_bridge_state *bridge_state,
> +					struct drm_crtc_state *crtc_state,
> +					struct drm_connector_state *conn_state,
> +					u32 output_fmt,
> +					unsigned int *num_input_fmts)
> +{
> +	u32 *input_fmts;
> +
> +	input_fmts = kmalloc(sizeof(*input_fmts), GFP_KERNEL);
> +	if (!input_fmts) {
> +		*num_input_fmts = 0;
> +		return NULL;
> +	}
> +
> +	input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA;
> +	*num_input_fmts = 1;
> +
> +	return input_fmts;
> +}
> +
> +static const struct drm_bridge_funcs it6263_bridge_funcs = {
> +	.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,
> +	.attach = it6263_bridge_attach,
> +	.mode_valid = it6263_bridge_mode_valid,
> +	.atomic_disable = it6263_bridge_atomic_disable,
> +	.atomic_enable = it6263_bridge_atomic_enable,
> +	.atomic_check = it6263_bridge_atomic_check,
> +	.detect = it6263_bridge_detect,
> +	.edid_read = it6263_bridge_edid_read,
> +	.atomic_get_input_bus_fmts = it6263_bridge_atomic_get_input_bus_fmts,
> +};
> +
> +static int it6263_probe(struct i2c_client *client) {
> +	struct device *dev = &client->dev;
> +	struct it6263 *it;
> +	int ret;
> +
> +	it = devm_kzalloc(dev, sizeof(*it), GFP_KERNEL);
> +	if (!it)
> +		return -ENOMEM;
> +
> +	it->dev = dev;
> +	it->hdmi_i2c = client;
> +
> +	it->hdmi_regmap = devm_regmap_init_i2c(client,
> +					       &it6263_hdmi_regmap_config);
> +	if (IS_ERR(it->hdmi_regmap))
> +		return dev_err_probe(dev, PTR_ERR(it->hdmi_regmap),
> +				     "failed to init I2C regmap for HDMI\n");
> +
> +	it->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
> +	if (IS_ERR(it->reset_gpio))
> +		return dev_err_probe(dev, PTR_ERR(it->reset_gpio),
> +				     "failed to get reset gpio\n");
> +
> +	ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(it6263_supplies),
> +					     it6263_supplies);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "failed to get power supplies\n");
> +
> +	ret = it6263_parse_dt(it);
> +	if (ret)
> +		return ret;
> +
> +	it6263_reset(it);
> +
> +	ret = it6263_lvds_set_i2c_addr(it);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "failed to set I2C addr\n");
> +
> +	it->lvds_i2c = devm_i2c_new_dummy_device(dev, client->adapter,
> +						 LVDS_INPUT_CTRL_I2C_ADDR);
> +	if (IS_ERR(it->lvds_i2c))
> +		dev_err_probe(it->dev, PTR_ERR(it->lvds_i2c),
> +			      "failed to allocate I2C device for LVDS\n");
> +
> +	it->lvds_regmap = devm_regmap_init_i2c(it->lvds_i2c,
> +					       &it6263_lvds_regmap_config);
> +	if (IS_ERR(it->lvds_regmap))
> +		return dev_err_probe(dev, PTR_ERR(it->lvds_regmap),
> +				     "failed to init I2C regmap for LVDS\n");
> +
> +	it6263_lvds_config(it);
> +	it6263_hdmi_config(it);
> +
> +	i2c_set_clientdata(client, it);
> +
> +	it->bridge.funcs = &it6263_bridge_funcs;
> +	it->bridge.of_node = dev->of_node;
> +	it->bridge.ops = DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_DETECT;
> +	drm_bridge_add(&it->bridge);
> +
> +	return 0;
> +}
> +
> +static void it6263_remove(struct i2c_client *client) {
> +	struct it6263 *it = i2c_get_clientdata(client);
> +
> +	drm_bridge_remove(&it->bridge);
> +}
> +
> +static const struct of_device_id it6263_of_match[] = {
> +	{ .compatible = "ite,it6263", },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, it6263_of_match);
> +
> +static const struct i2c_device_id it6263_i2c_ids[] = {
> +	{ "it6263", 0 },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(i2c, it6263_i2c_ids);
> +
> +static struct i2c_driver it6263_driver = {
> +	.probe = it6263_probe,
> +	.remove = it6263_remove,
> +	.driver = {
> +		.name = "it6263",
> +		.of_match_table = it6263_of_match,
> +	},
> +	.id_table = it6263_i2c_ids,
> +};
> +module_i2c_driver(it6263_driver);
> +
> +MODULE_DESCRIPTION("ITE Tech. Inc. IT6263 LVDS/HDMI bridge");
> +MODULE_AUTHOR("Liu Ying <victor.liu@nxp.com>"); MODULE_LICENSE("GPL");
> --
> 2.34.1
> 


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

* Re: [PATCH 5/8] dt-bindings: display: bridge: Add ITE IT6263 LVDS to HDMI converter
  2024-10-02  0:02   ` Rob Herring
@ 2024-10-09  7:00     ` Liu Ying
  0 siblings, 0 replies; 38+ messages in thread
From: Liu Ying @ 2024-10-09  7:00 UTC (permalink / raw)
  To: Rob Herring
  Cc: dri-devel, devicetree, linux-kernel, imx, linux-arm-kernel,
	andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart, jonas,
	jernej.skrabec, maarten.lankhorst, mripard, tzimmermann, airlied,
	simona, krzk+dt, conor+dt, shawnguo, s.hauer, kernel, festevam,
	catalin.marinas, will, quic_bjorande, geert+renesas,
	dmitry.baryshkov, arnd, nfraprado, o.rempel, y.moog

Hi Rob,

On 10/02/2024, Rob Herring wrote:
> On Mon, Sep 30, 2024 at 01:29:00PM +0800, Liu Ying wrote:
>> Document ITE IT6263 LVDS to HDMI converter.
>>
>> Product link:
>> https://www.ite.com.tw/en/product/cate1/IT6263
>>
>> Signed-off-by: Liu Ying <victor.liu@nxp.com>
>> ---
>>  .../bindings/display/bridge/ite,it6263.yaml   | 310 ++++++++++++++++++
>>  1 file changed, 310 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml
>>
>> diff --git a/Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml b/Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml
>> new file mode 100644
>> index 000000000000..97fb81e5bc4a
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml
>> @@ -0,0 +1,310 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/display/bridge/ite,it6263.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: ITE IT6263 LVDS to HDMI converter
>> +
>> +maintainers:
>> +  - Liu Ying <victor.liu@nxp.com>
>> +
>> +description: |
>> +  The IT6263 is a high-performance single-chip De-SSC(De-Spread Spectrum) LVDS
>> +  to HDMI converter.  Combined with LVDS receiver and HDMI 1.4a transmitter,
>> +  the IT6263 supports LVDS input and HDMI 1.4 output by conversion function.
>> +  The built-in LVDS receiver can support single-link and dual-link LVDS inputs,
>> +  and the built-in HDMI transmitter is fully compliant with HDMI 1.4a/3D, HDCP
>> +  1.2 and backward compatible with DVI 1.0 specification.
>> +
>> +  The IT6263 also encodes and transmits up to 8 channels of I2S digital audio,
>> +  with sampling rate up to 192KHz and sample size up to 24 bits. In addition,
>> +  an S/PDIF input port takes in compressed audio of up to 192KHz frame rate.
>> +
>> +  The newly supported High-Bit Rate(HBR) audio by HDMI specifications v1.3 is
>> +  provided by the IT6263 in two interfaces: the four I2S input ports or the
>> +  S/PDIF input port.  With both interfaces the highest possible HBR frame rate
>> +  is supported at up to 768KHz.
>> +
>> +properties:
>> +  compatible:
>> +    const: ite,it6263
>> +
>> +  reg:
>> +    maxItems: 1
>> +
>> +  clocks:
>> +    maxItems: 1
>> +    description: audio master clock
>> +
>> +  clock-names:
>> +    const: mclk
>> +
>> +  reset-gpios:
>> +    maxItems: 1
>> +
>> +  ivdd-supply:
>> +    description: 1.8V digital logic power
>> +
>> +  ovdd-supply:
>> +    description: 3.3V I/O pin power
>> +
>> +  txavcc18-supply:
>> +    description: 1.8V HDMI analog frontend power
>> +
>> +  txavcc33-supply:
>> +    description: 3.3V HDMI analog frontend power
>> +
>> +  pvcc1-supply:
>> +    description: 1.8V HDMI frontend core PLL power
>> +
>> +  pvcc2-supply:
>> +    description: 1.8V HDMI frontend filter PLL power
>> +
>> +  avcc-supply:
>> +    description: 3.3V LVDS frontend power
>> +
>> +  anvdd-supply:
>> +    description: 1.8V LVDS frontend analog power
>> +
>> +  apvdd-supply:
>> +    description: 1.8V LVDS frontend PLL power
>> +
>> +  "#sound-dai-cells":
>> +    const: 0
>> +
>> +  ite,i2s-audio-fifo-sources:
>> +    $ref: /schemas/types.yaml#/definitions/uint32-array
>> +    minItems: 1
>> +    maxItems: 4
>> +    items:
>> +      enum: [0, 1, 2, 3]
>> +    description:
>> +      Each array element indicates the pin number of an I2S serial data input
>> +      line which is connected to an audio FIFO, from audio FIFO0 to FIFO3.
>> +
>> +  ite,rl-channel-swap-audio-sources:
>> +    $ref: /schemas/types.yaml#/definitions/uint32-array
>> +    minItems: 1
>> +    maxItems: 4
>> +    uniqueItems: true
>> +    items:
>> +      enum: [0, 1, 2, 3]
>> +    description:
>> +      Each array element indicates an audio source whose right channel and left
>> +      channel are swapped by this converter. For I2S, the element is the pin
>> +      number of an I2S serial data input line. For S/PDIF, the element is always
>> +      0.
>> +
>> +  ports:
>> +    $ref: /schemas/graph.yaml#/properties/ports
> 
> Test your bindings. You need 'additionalProperties: false' here. Though 
> I can't remember if that can 'see' properties under the oneOf. So it may 
> have to be unevaluatedProperties instead.

Ah, I see the same warnings with your bot after upgrading my local dtschema
to dtschema-2024.9. I should have upgraded it earlier, sorry. Before sending
this patch, I tested it with dtschema-2024.2 and there is no warning.

However, there are still the warnings after adding additionalProperties or 
unevaluatedProperties constraint here. With additionalProperties, there are
even some additional errors.  Thoughts?

> 
>> +
>> +    oneOf:
> 
> I think you can get rid of this. If port@1 requires the dual link 
> properties and then properties on port@0, then the only way you can have 
> a single link is removing port@1 from the DT. 

If I get rid of this with the below snippet, I see warnings against
the single-link LVDS input example. It looks like the conditions in
"allOf" are still true even if "port@1" is not in that example.

And it seems difficult to disallow people to add "dual-lvds-odd-pixels"
and/or "dual-lvds-even-pixels" properties to "port@0" when there is no
"port@1". This is not an issue if we use the "oneOf" to separate the
single/dual link cases. Any ideas?

-----------------------------8<-----------------------------
  ports:                                                                         
    $ref: /schemas/graph.yaml#/properties/ports                                  
                                                                                 
    properties:                                                                  
      port@0:                                                                    
        $ref: /schemas/graph.yaml#/$defs/port-base                               
        unevaluatedProperties: false                                             
        description: the first LVDS input link                                   
                                                                                 
        properties:                                                              
          dual-lvds-odd-pixels:                                                  
            type: boolean                                                        
            description: the first sink port for odd pixels                      
                                                                                 
          dual-lvds-even-pixels:                                                 
            type: boolean                                                        
            description: the first sink port for even pixels                     
                                                                                 
      port@1:                                                                    
        $ref: /schemas/graph.yaml#/$defs/port-base                               
        unevaluatedProperties: false                                             
        description: the second LVDS input link                                  
                                                                                 
        properties:                                                              
          dual-lvds-even-pixels:                                                 
            type: boolean                                                        
            description: the second sink port for even pixels                    
                                                                                 
          dual-lvds-odd-pixels:                                                  
            type: boolean                                                        
            description: the second sink port for odd pixels                     
                                                                                 
        oneOf:                                                                   
          - required: [dual-lvds-even-pixels]                                    
          - required: [dual-lvds-odd-pixels]                                     
                                                                                 
      port@2:                                                                    
        $ref: /schemas/graph.yaml#/properties/port                               
        description: video port for the HDMI output                              
                                                                                 
      port@3:                                                                    
        $ref: /schemas/graph.yaml#/properties/port                               
        description: sound input port                                            
                                                                                 
    required:                                                                    
      - port@0                                                                   
      - port@2

    allOf:                                                                       
      - if:                                                                      
          properties:                                                            
            port@1:                                                              
              required:                                                          
                - dual-lvds-odd-pixels                                           
        then:                                                                    
          properties:                                                            
            port@0:                                                              
              required:                                                          
                - dual-lvds-even-pixels                                          
                                                                                 
      - if:                                                                      
          properties:                                                            
            port@1:                                                              
              required:                                                          
                - dual-lvds-even-pixels                                          
        then:                                                                    
          properties:                                                            
            port@0:                                                              
              required:                                                          
                - dual-lvds-odd-pixels                        
-----------------------------8<-----------------------------

Documentation/devicetree/bindings/display/bridge/ite,it6263.example.dtb: hdmi@4c: ports:port@0: 'dual-lvds-even-pixels' is a required property
	from schema $id: http://devicetree.org/schemas/display/bridge/ite,it6263.yaml#
Documentation/devicetree/bindings/display/bridge/ite,it6263.example.dtb: hdmi@4c: ports:port@0: 'dual-lvds-odd-pixels' is a required property
	from schema $id: http://devicetree.org/schemas/display/bridge/ite,it6263.yaml#

> 
>> +      - properties:
>> +          port@0:
>> +            $ref: /schemas/graph.yaml#/properties/port
>> +            description: the first LVDS input link
>> +
>> +          port@1: false
>> +
>> +          port@2:
>> +            $ref: /schemas/graph.yaml#/properties/port
>> +            description: video port for the HDMI output
>> +
>> +          port@3:
>> +            $ref: /schemas/graph.yaml#/properties/port
>> +            description: sound input port
>> +
>> +        required:
>> +          - port@0
>> +          - port@2
>> +
>> +      - properties:
>> +          port@0:
>> +            $ref: /schemas/graph.yaml#/$defs/port-base
>> +            unevaluatedProperties: false
>> +            description: the first LVDS input link
>> +
>> +            properties:
>> +              dual-lvds-odd-pixels:
>> +                type: boolean
>> +                description: the first sink port for odd pixels
>> +
>> +              dual-lvds-even-pixels:
>> +                type: boolean
>> +                description: the first sink port for even pixels
>> +
>> +            oneOf:
>> +              - required: [dual-lvds-odd-pixels]
>> +              - required: [dual-lvds-even-pixels]
>> +
>> +          port@1:
>> +            $ref: /schemas/graph.yaml#/$defs/port-base
>> +            unevaluatedProperties: false
>> +            description: the second LVDS input link
>> +
>> +            properties:
>> +              dual-lvds-even-pixels:
>> +                type: boolean
>> +                description: the second sink port for even pixels
>> +
>> +              dual-lvds-odd-pixels:
>> +                type: boolean
>> +                description: the second sink port for odd pixels
>> +
>> +            oneOf:
>> +              - required: [dual-lvds-even-pixels]
>> +              - required: [dual-lvds-odd-pixels]
>> +
>> +          port@2:
>> +            $ref: /schemas/graph.yaml#/properties/port
>> +            description: video port for the HDMI output
>> +
>> +          port@3:
>> +            $ref: /schemas/graph.yaml#/properties/port
>> +            description: sound input port
>> +
>> +        required:
>> +          - port@0
>> +          - port@1
>> +          - port@2
>> +
>> +        allOf:
>> +          - if:
>> +              properties:
>> +                port@0:
>> +                  required:
>> +                    - dual-lvds-odd-pixels
>> +            then:
>> +              properties:
>> +                port@1:
>> +                  properties:
>> +                    dual-lvds-odd-pixels: false
>> +
>> +          - if:
>> +              properties:
>> +                port@0:
>> +                  required:
>> +                    - dual-lvds-even-pixels
>> +            then:
>> +              properties:
>> +                port@1:
>> +                  properties:
>> +                    dual-lvds-even-pixels: false
>> +
>> +required:
>> +  - compatible
>> +  - reg
>> +  - ivdd-supply
>> +  - ovdd-supply
>> +  - txavcc18-supply
>> +  - txavcc33-supply
>> +  - pvcc1-supply
>> +  - pvcc2-supply
>> +  - avcc-supply
>> +  - anvdd-supply
>> +  - apvdd-supply
>> +  - ports
>> +
>> +additionalProperties: false
>> +

-- 
Regards,
Liu Ying


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

* Re: [PATCH 5/8] dt-bindings: display: bridge: Add ITE IT6263 LVDS to HDMI converter
  2024-09-30 13:18     ` Biju Das
@ 2024-10-09  7:51       ` Liu Ying
  0 siblings, 0 replies; 38+ messages in thread
From: Liu Ying @ 2024-10-09  7:51 UTC (permalink / raw)
  To: Biju Das, dri-devel@lists.freedesktop.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linux-arm-kernel@lists.infradead.org
  Cc: andrzej.hajda@intel.com, neil.armstrong@linaro.org,
	rfoss@kernel.org, laurent.pinchart, jonas@kwiboo.se,
	jernej.skrabec@gmail.com, maarten.lankhorst@linux.intel.com,
	mripard@kernel.org, tzimmermann@suse.de, airlied@gmail.com,
	simona@ffwll.ch, robh@kernel.org, krzk+dt@kernel.org,
	conor+dt@kernel.org, shawnguo@kernel.org, s.hauer@pengutronix.de,
	kernel@pengutronix.de, festevam@gmail.com,
	catalin.marinas@arm.com, will@kernel.org,
	quic_bjorande@quicinc.com, geert+renesas@glider.be,
	dmitry.baryshkov@linaro.org, arnd@arndb.de,
	nfraprado@collabora.com, o.rempel@pengutronix.de,
	y.moog@phytec.de

On 09/30/2024, Biju Das wrote:
> Hi Liu,

Hi Biju,

> 
>> -----Original Message-----
>> From: Biju Das
>> Sent: Monday, September 30, 2024 10:04 AM
>> Subject: RE: [PATCH 5/8] dt-bindings: display: bridge: Add ITE IT6263 LVDS to HDMI converter
>>
>> Hi Liu,
>>
>> thanks for the patch.
>>
>>> -----Original Message-----
>>> From: linux-arm-kernel <linux-arm-kernel-bounces@lists.infradead.org>
>>> On Behalf Of Liu Ying
>>> Sent: Monday, September 30, 2024 6:29 AM
>>> Subject: [PATCH 5/8] dt-bindings: display: bridge: Add ITE IT6263 LVDS
>>> to HDMI converter
>>>
>>> Document ITE IT6263 LVDS to HDMI converter.
>>>
>>> Product link:
>>> https://www.ite.com.tw/en/product/cate1/IT6263
>>>
>>> Signed-off-by: Liu Ying <victor.liu@nxp.com>
>>> ---
>>>  .../bindings/display/bridge/ite,it6263.yaml   | 310 ++++++++++++++++++
>>>  1 file changed, 310 insertions(+)
>>>  create mode 100644
>>> Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml
>>>
>>> diff --git
>>> a/Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml
>>> b/Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml
>>> new file mode 100644
>>> index 000000000000..97fb81e5bc4a
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml
>>> @@ -0,0 +1,310 @@
>>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2
>>> +---
>>> +$id: http://devicetree.org/schemas/display/bridge/ite,it6263.yaml#
>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>> +
>>> +title: ITE IT6263 LVDS to HDMI converter
>>> +
>>> +maintainers:
>>> +  - Liu Ying <victor.liu@nxp.com>
>>> +
>>> +description: |
>>> +  The IT6263 is a high-performance single-chip De-SSC(De-Spread
>>> +Spectrum) LVDS
>>> +  to HDMI converter.  Combined with LVDS receiver and HDMI 1.4a
>>> +transmitter,
>>> +  the IT6263 supports LVDS input and HDMI 1.4 output by conversion function.
>>> +  The built-in LVDS receiver can support single-link and dual-link
>>> +LVDS inputs,
>>> +  and the built-in HDMI transmitter is fully compliant with HDMI
>>> +1.4a/3D, HDCP
>>> +  1.2 and backward compatible with DVI 1.0 specification.
>>> +
>>> +  The IT6263 also encodes and transmits up to 8 channels of I2S
>>> + digital audio,  with sampling rate up to 192KHz and sample size up to 24 bits.
>>> + In addition,  an S/PDIF input port takes in compressed audio of up to 192KHz frame rate.
>>> +
>>> +  The newly supported High-Bit Rate(HBR) audio by HDMI specifications
>>> + v1.3 is  provided by the IT6263 in two interfaces: the four I2S
>>> + input ports or the  S/PDIF input port.  With both interfaces the
>>> + highest possible HBR frame rate  is supported at up to 768KHz.
>>> +
>>> +properties:
>>> +  compatible:
>>> +    const: ite,it6263
>>> +
>>> +  reg:
>>> +    maxItems: 1
>>> +
>>> +  clocks:
>>> +    maxItems: 1
>>> +    description: audio master clock
>>> +
>>> +  clock-names:
>>> +    const: mclk
>>> +
>>> +  reset-gpios:
>>> +    maxItems: 1
>>> +
>>> +  ivdd-supply:
>>> +    description: 1.8V digital logic power
>>> +
>>> +  ovdd-supply:
>>> +    description: 3.3V I/O pin power
>>> +
>>> +  txavcc18-supply:
>>> +    description: 1.8V HDMI analog frontend power
>>> +
>>> +  txavcc33-supply:
>>> +    description: 3.3V HDMI analog frontend power
>>> +
>>> +  pvcc1-supply:
>>> +    description: 1.8V HDMI frontend core PLL power
>>> +
>>> +  pvcc2-supply:
>>> +    description: 1.8V HDMI frontend filter PLL power
>>> +
>>> +  avcc-supply:
>>> +    description: 3.3V LVDS frontend power
>>> +
>>> +  anvdd-supply:
>>> +    description: 1.8V LVDS frontend analog power
>>> +
>>> +  apvdd-supply:
>>> +    description: 1.8V LVDS frontend PLL power
>>> +
>>> +  "#sound-dai-cells":
>>> +    const: 0
>>> +
>>> +  ite,i2s-audio-fifo-sources:
>>> +    $ref: /schemas/types.yaml#/definitions/uint32-array
>>> +    minItems: 1
>>> +    maxItems: 4
>>> +    items:
>>> +      enum: [0, 1, 2, 3]
>>> +    description:
>>> +      Each array element indicates the pin number of an I2S serial data input
>>> +      line which is connected to an audio FIFO, from audio FIFO0 to FIFO3.
>>> +
>>> +  ite,rl-channel-swap-audio-sources:
>>> +    $ref: /schemas/types.yaml#/definitions/uint32-array
>>> +    minItems: 1
>>> +    maxItems: 4
>>> +    uniqueItems: true
>>> +    items:
>>> +      enum: [0, 1, 2, 3]
>>> +    description:
>>> +      Each array element indicates an audio source whose right channel and left
>>> +      channel are swapped by this converter. For I2S, the element is the pin
>>> +      number of an I2S serial data input line. For S/PDIF, the element is always
>>> +      0.
>>> +
>>> +  ports:
>>> +    $ref: /schemas/graph.yaml#/properties/ports
>>> +
>>> +    oneOf:
>>> +      - properties:
>>> +          port@0:
>>> +            $ref: /schemas/graph.yaml#/properties/port
>>> +            description: the first LVDS input link
>>> +
>>> +          port@1: false
>>> +
>>> +          port@2:
>>> +            $ref: /schemas/graph.yaml#/properties/port
>>> +            description: video port for the HDMI output
>>> +
>>> +          port@3:
>>> +            $ref: /schemas/graph.yaml#/properties/port
>>> +            description: sound input port
>>> +
>>> +        required:
>>> +          - port@0
>>> +          - port@2
>>> +
>>> +      - properties:
>>> +          port@0:
>>> +            $ref: /schemas/graph.yaml#/$defs/port-base
>>> +            unevaluatedProperties: false
>>> +            description: the first LVDS input link
>>> +
>>> +            properties:
>>> +              dual-lvds-odd-pixels:
>>> +                type: boolean
>>> +                description: the first sink port for odd pixels
>>> +
>>> +              dual-lvds-even-pixels:
>>> +                type: boolean
>>> +                description: the first sink port for even pixels
>>> +
>>> +            oneOf:
>>> +              - required: [dual-lvds-odd-pixels]
>>> +              - required: [dual-lvds-even-pixels]
>>> +
>>> +          port@1:
>>> +            $ref: /schemas/graph.yaml#/$defs/port-base
>>> +            unevaluatedProperties: false
>>> +            description: the second LVDS input link
>>> +
>>> +            properties:
>>> +              dual-lvds-even-pixels:
>>> +                type: boolean
>>> +                description: the second sink port for even pixels
>>> +
>>> +              dual-lvds-odd-pixels:
>>> +                type: boolean
>>> +                description: the second sink port for odd pixels
>>> +
>>> +            oneOf:
>>> +              - required: [dual-lvds-even-pixels]
>>> +              - required: [dual-lvds-odd-pixels]
>>
>>
>>> +
>>> +          port@2:
>>> +            $ref: /schemas/graph.yaml#/properties/port
>>> +            description: video port for the HDMI output
>>> +
>>> +          port@3:
>>> +            $ref: /schemas/graph.yaml#/properties/port
>>> +            description: sound input port
>>
>> What about single lvds as device support it?
>>
>> Cheers,
>> Biju
>>
>>> +
>>> +        required:
>>> +          - port@0
>>> +          - port@1
>>> +          - port@2
>>> +
>>> +        allOf:
>>> +          - if:
>>> +              properties:
>>> +                port@0:
>>> +                  required:
>>> +                    - dual-lvds-odd-pixels
>>> +            then:
>>> +              properties:
>>> +                port@1:
>>> +                  properties:
>>> +                    dual-lvds-odd-pixels: false
>>> +
>>> +          - if:
>>> +              properties:
>>> +                port@0:
>>> +                  required:
>>> +                    - dual-lvds-even-pixels
>>> +            then:
>>> +              properties:
>>> +                port@1:
>>> +                  properties:
>>> +                    dual-lvds-even-pixels: false
> 
> Do we need to document ite,data-mapping to support both VESA and JEIDA formats??
> 
> Or
> 
> Is there any run time info available to get this info? Currently,
> I see it is hardcoded in driver.

I think there are two options:
1) Reference the data-mapping property in lvds-data-mapping.yaml
   Question is that only jeida-18, jeida-24 and vesa-24 are
   enumerated, while IT6263 supports something like jeida-30 and
   vesa-30(not sure if they are standarized or not) with 5 data
   lanes(A-E) per LVDS link as the LVDS mapping table in IT6263
   datasheet mentions.

2) Document the number of data lanes per LVDS link
   This is enough. data-mapping is kind of too much information
   from DT point of view. Linux display bridge drivers support
   runtime bus format negotiation to determine the data mapping.
   So maybe a property like this is ok:

   ite,lvds-link-num-data-lanes:                                                  
    $ref: /schemas/types.yaml#/definitions/uint8                                 
    enum: [3, 4, 5]

   BTW, I only tested 4 data lanes. Not sure if the other 2 work
   or not.

Laurent, Rob, any thoughts?

> 
> Cheers,
> Biju
> 
>>> +
>>> +required:
>>> +  - compatible
>>> +  - reg
>>> +  - ivdd-supply
>>> +  - ovdd-supply
>>> +  - txavcc18-supply
>>> +  - txavcc33-supply
>>> +  - pvcc1-supply
>>> +  - pvcc2-supply
>>> +  - avcc-supply
>>> +  - anvdd-supply
>>> +  - apvdd-supply
>>> +  - ports
>>> +
>>> +additionalProperties: false
>>> +
>>> +examples:
>>> +  - |
>>> +    /* single-link LVDS input */
>>> +    #include <dt-bindings/gpio/gpio.h>
>>> +
>>> +    i2c {
>>> +        #address-cells = <1>;
>>> +        #size-cells = <0>;
>>> +
>>> +        hdmi@4c {
>>> +            compatible = "ite,it6263";
>>> +            reg = <0x4c>;
>>> +            reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
>>> +            ivdd-supply = <&reg_buck5>;
>>> +            ovdd-supply = <&reg_vext_3v3>;
>>> +            txavcc18-supply = <&reg_buck5>;
>>> +            txavcc33-supply = <&reg_vext_3v3>;
>>> +            pvcc1-supply = <&reg_buck5>;
>>> +            pvcc2-supply = <&reg_buck5>;
>>> +            avcc-supply = <&reg_vext_3v3>;
>>> +            anvdd-supply = <&reg_buck5>;
>>> +            apvdd-supply = <&reg_buck5>;
>>> +
>>> +            ports {
>>> +                #address-cells = <1>;
>>> +                #size-cells = <0>;
>>> +
>>> +                port@0 {
>>> +                    reg = <0>;
>>> +
>>> +                    it6263_lvds_link1: endpoint {
>>> +                        remote-endpoint = <&ldb_lvds_ch0>;
>>> +                    };
>>> +                };
>>> +
>>> +                port@2 {
>>> +                    reg = <2>;
>>> +
>>> +                    it6263_out: endpoint {
>>> +                        remote-endpoint = <&hdmi_in>;
>>> +                    };
>>> +                };
>>> +            };
>>> +        };
>>> +    };
>>> +
>>> +  - |
>>> +    /* dual-link LVDS input */
>>> +    #include <dt-bindings/gpio/gpio.h>
>>> +
>>> +    i2c {
>>> +        #address-cells = <1>;
>>> +        #size-cells = <0>;
>>> +
>>> +        hdmi@4c {
>>> +            compatible = "ite,it6263";
>>> +            reg = <0x4c>;
>>> +            reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
>>> +            ivdd-supply = <&reg_buck5>;
>>> +            ovdd-supply = <&reg_vext_3v3>;
>>> +            txavcc18-supply = <&reg_buck5>;
>>> +            txavcc33-supply = <&reg_vext_3v3>;
>>> +            pvcc1-supply = <&reg_buck5>;
>>> +            pvcc2-supply = <&reg_buck5>;
>>> +            avcc-supply = <&reg_vext_3v3>;
>>> +            anvdd-supply = <&reg_buck5>;
>>> +            apvdd-supply = <&reg_buck5>;
>>> +
>>> +            ports {
>>> +                #address-cells = <1>;
>>> +                #size-cells = <0>;
>>> +
>>> +                port@0 {
>>> +                    reg = <0>;
>>> +                    dual-lvds-odd-pixels;
>>> +
>>> +                    it6263_lvds_link1_dual: endpoint {
>>> +                        remote-endpoint = <&ldb_lvds_ch0>;
>>> +                    };
>>> +                };
>>> +
>>> +                port@1 {
>>> +                    reg = <1>;
>>> +                    dual-lvds-even-pixels;
>>> +
>>> +                    it6263_lvds_link2_dual: endpoint {
>>> +                        remote-endpoint = <&ldb_lvds_ch1>;
>>> +                    };
>>> +                };
>>> +
>>> +                port@2 {
>>> +                    reg = <2>;
>>> +
>>> +                    it6263_out_dual: endpoint {
>>> +                        remote-endpoint = <&hdmi_in>;
>>> +                    };
>>> +                };
>>> +            };
>>> +        };
>>> +    };
>>> --
>>> 2.34.1
>>>
> 

-- 
Regards,
Liu Ying


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

* Re: [PATCH 6/8] drm/bridge: Add ITE IT6263 LVDS to HDMI converter
  2024-09-30 13:10     ` Biju Das
@ 2024-10-09  8:33       ` Liu Ying
  2024-10-09 17:02         ` Dmitry Baryshkov
  0 siblings, 1 reply; 38+ messages in thread
From: Liu Ying @ 2024-10-09  8:33 UTC (permalink / raw)
  To: Biju Das, dri-devel@lists.freedesktop.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linux-arm-kernel@lists.infradead.org
  Cc: andrzej.hajda@intel.com, neil.armstrong@linaro.org,
	rfoss@kernel.org, laurent.pinchart, jonas@kwiboo.se,
	jernej.skrabec@gmail.com, maarten.lankhorst@linux.intel.com,
	mripard@kernel.org, tzimmermann@suse.de, airlied@gmail.com,
	simona@ffwll.ch, robh@kernel.org, krzk+dt@kernel.org,
	conor+dt@kernel.org, shawnguo@kernel.org, s.hauer@pengutronix.de,
	kernel@pengutronix.de, festevam@gmail.com,
	catalin.marinas@arm.com, will@kernel.org,
	quic_bjorande@quicinc.com, geert+renesas@glider.be,
	dmitry.baryshkov@linaro.org, arnd@arndb.de,
	nfraprado@collabora.com, o.rempel@pengutronix.de,
	y.moog@phytec.de

On 09/30/2024, Biju Das wrote:
> Hi Liu,

Hi Biju,

> 
>> -----Original Message-----
>> From: Biju Das
>> Sent: Monday, September 30, 2024 10:16 AM
>> Subject: RE: [PATCH 6/8] drm/bridge: Add ITE IT6263 LVDS to HDMI converter
>>
>> Hi Liu,
>>
>> Thanks for the patch.
>>
>>> -----Original Message-----
>>> From: linux-arm-kernel <linux-arm-kernel-bounces@lists.infradead.org>
>>> On Behalf Of Liu Ying
>>> Sent: Monday, September 30, 2024 6:29 AM
>>> Subject: [PATCH 6/8] drm/bridge: Add ITE IT6263 LVDS to HDMI converter
>>>
>>> Add basic HDMI video output support. Currently, only RGB888 output
>>> pixel format is supported.  At the LVDS input side, the driver
>>> supports single LVDS link and dual LVDS links with "jeida-24" LVDS mapping.
>>>
>>> Product link:
>>> https://www.ite.com.tw/en/product/cate1/IT6263
>>>
>>> Signed-off-by: Liu Ying <victor.liu@nxp.com>
>>> ---
>>>  drivers/gpu/drm/bridge/Kconfig      |   8 +
>>>  drivers/gpu/drm/bridge/Makefile     |   1 +
>>>  drivers/gpu/drm/bridge/ite-it6263.c | 829
>>> ++++++++++++++++++++++++++++
>>>  3 files changed, 838 insertions(+)
>>>  create mode 100644 drivers/gpu/drm/bridge/ite-it6263.c
>>>
>>> diff --git a/drivers/gpu/drm/bridge/Kconfig
>>> b/drivers/gpu/drm/bridge/Kconfig index
>>> 3eb955333c80..93f99682a090 100644
>>> --- a/drivers/gpu/drm/bridge/Kconfig
>>> +++ b/drivers/gpu/drm/bridge/Kconfig
>>> @@ -90,6 +90,14 @@ config DRM_FSL_LDB
>>>  	help
>>>  	  Support for i.MX8MP DPI-to-LVDS on-SoC encoder.
>>>
>>> +config DRM_ITE_IT6263
>>> +	tristate "ITE IT6263 LVDS/HDMI bridge"
>>> +	depends on OF
>>> +	select DRM_KMS_HELPER
>>> +	select REGMAP_I2C
>>> +	help
>>> +	  ITE IT6263 LVDS to HDMI bridge chip driver.
>>> +
>>>  config DRM_ITE_IT6505
>>>  	tristate "ITE IT6505 DisplayPort bridge"
>>>  	depends on OF
>>> diff --git a/drivers/gpu/drm/bridge/Makefile
>>> b/drivers/gpu/drm/bridge/Makefile index 7df87b582dca..f3776dd473fd
>>> 100644
>>> --- a/drivers/gpu/drm/bridge/Makefile
>>> +++ b/drivers/gpu/drm/bridge/Makefile
>>> @@ -6,6 +6,7 @@ obj-$(CONFIG_DRM_CHRONTEL_CH7033) += chrontel-ch7033.o
>>>  obj-$(CONFIG_DRM_CROS_EC_ANX7688) += cros-ec-anx7688.o
>>>  obj-$(CONFIG_DRM_DISPLAY_CONNECTOR) += display-connector.o
>>>  obj-$(CONFIG_DRM_FSL_LDB) += fsl-ldb.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
>>>  obj-$(CONFIG_DRM_LONTIUM_LT9211) += lontium-lt9211.o diff --git
>>> a/drivers/gpu/drm/bridge/ite-it6263.c
>>> b/drivers/gpu/drm/bridge/ite-it6263.c
>>> new file mode 100644
>>> index 000000000000..886588497bc1
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/bridge/ite-it6263.c
>>> @@ -0,0 +1,829 @@
>>> +// SPDX-License-Identifier: GPL-2.0
>>> +/*
>>> + * Copyright 2024 NXP
>>> + */
>>> +
>>> +#include <linux/bitfield.h>
>>> +#include <linux/bits.h>
>>> +#include <linux/delay.h>
>>> +#include <linux/gpio/consumer.h>
>>> +#include <linux/i2c.h>
>>> +#include <linux/media-bus-format.h>
>>> +#include <linux/module.h>
>>> +#include <linux/of.h>
>>> +#include <linux/regmap.h>
>>> +#include <linux/regulator/consumer.h>
>>> +
>>> +#include <drm/drm_atomic.h>
>>> +#include <drm/drm_atomic_helper.h>
>>> +#include <drm/drm_atomic_state_helper.h> #include <drm/drm_bridge.h>
>>> +#include <drm/drm_connector.h> #include <drm/drm_crtc.h> #include
>>> +<drm/drm_edid.h> #include <drm/drm_of.h> #include
>>> +<drm/drm_probe_helper.h>
>>> +
>>> +/*
>>> +---------------------------------------------------------------------
>>> +--
>>> +------
>>> + * LVDS registers
>>> + */
>>> +
>>> +/* LVDS software reset registers */
>>> +#define LVDS_REG_05			0x05
>>> +#define  REG_SOFT_P_RST			BIT(1)
>>> +
>>> +/* LVDS system configuration registers */
>>> +/* 0x0b */
>>> +#define LVDS_REG_0B			0x0b
>>> +#define  REG_SSC_PCLK_RF		BIT(0)
>>> +#define  REG_LVDS_IN_SWAP		BIT(1)
>>> +
>>> +/* LVDS test pattern gen control registers */
>>> +/* 0x2c */
>>> +#define LVDS_REG_2C			0x2c
>>> +#define  REG_COL_DEP			GENMASK(1, 0)
>>> +#define  BIT8				FIELD_PREP(REG_COL_DEP, 2)
>>> +#define  OUT_MAP			BIT(4)
>>> +#define  JEIDA				0
>>> +#define  REG_DESSC_ENB			BIT(6)
>>> +#define  DMODE				BIT(7)
>>> +#define  DISO				BIT(7)
>>> +#define  SISO				0
>>> +
>>> +#define LVDS_REG_3C			0x3c
>>> +#define LVDS_REG_3F			0x3f
>>> +#define LVDS_REG_47			0x47
>>> +#define LVDS_REG_48			0x48
>>> +#define LVDS_REG_4F			0x4f
>>> +#define LVDS_REG_52			0x52
>>> +
>>> +/*
>>> +---------------------------------------------------------------------
>>> +--
>>> +------
>>> + * HDMI registers are separated into three banks:
>>> + * 1) HDMI register common bank: 0x00 ~ 0x2f  */
>>> +
>>> +/* HDMI genernal registers */
>>> +#define HDMI_REG_SW_RST			0x04
>>> +#define  SOFTREF_RST			BIT(5)
>>> +#define  SOFTA_RST			BIT(4)
>>> +#define  SOFTV_RST			BIT(3)
>>> +#define  AUD_RST			BIT(2)
>>> +#define  HDCP_RST			BIT(0)
>>> +#define  HDMI_RST_ALL			(SOFTREF_RST | SOFTA_RST | SOFTV_RST | \
>>> +					 AUD_RST | HDCP_RST)
>>> +
>>> +#define HDMI_REG_SYS_STATUS		0x0e
>>> +#define  HPDETECT			BIT(6)
>>> +#define  TXVIDSTABLE			BIT(4)
>>> +
>>> +#define HDMI_REG_BANK_CTRL		0x0f
>>> +#define  REG_BANK_SEL			BIT(0)
>>> +
>>> +/* HDMI System DDC control registers */
>>> +#define HDMI_REG_DDC_MASTER_CTRL	0x10
>>> +#define  MASTER_SEL_HOST		BIT(0)
>>> +
>>> +#define HDMI_REG_DDC_HEADER		0x11
>>> +
>>> +#define HDMI_REG_DDC_REQOFF		0x12
>>> +#define HDMI_REG_DDC_REQCOUNT		0x13
>>> +#define HDMI_REG_DDC_EDIDSEG		0x14
>>> +
>>> +#define HDMI_REG_DDC_CMD		0x15
>>> +#define  DDC_CMD_EDID_READ		0x3
>>> +#define  DDC_CMD_FIFO_CLR		0x9
>>> +
>>> +#define HDMI_REG_DDC_STATUS		0x16
>>> +#define  DDC_DONE			BIT(7)
>>> +#define  DDC_NOACK			BIT(5)
>>> +#define  DDC_WAITBUS			BIT(4)
>>> +#define  DDC_ARBILOSE			BIT(3)
>>> +#define  DDC_ERROR			(DDC_NOACK | DDC_WAITBUS | DDC_ARBILOSE)
>>> +
>>> +#define HDMI_DDC_FIFO_BYTES		32
>>> +#define HDMI_REG_DDC_READFIFO		0x17
>>> +#define HDMI_REG_LVDS_PORT		0x1d /* LVDS input control I2C addr */
>>> +#define HDMI_REG_LVDS_PORT_EN		0x1e
>>> +#define LVDS_INPUT_CTRL_I2C_ADDR	0x33
>>> +
>>> +/*
>>> +---------------------------------------------------------------------
>>> +--
>>> +------
>>> + * 2) HDMI register bank0: 0x30 ~ 0xff  */
>>> +
>>> +/* HDMI AFE registers */
>>> +#define HDMI_REG_AFE_DRV_CTRL		0x61
>>> +#define  AFE_DRV_PWD			BIT(5)
>>> +#define  AFE_DRV_RST			BIT(4)
>>> +
>>> +#define HDMI_REG_AFE_XP_CTRL		0x62
>>> +#define  AFE_XP_GAINBIT			BIT(7)
>>> +#define  AFE_XP_ER0			BIT(4)
>>> +#define  AFE_XP_RESETB			BIT(3)
>>> +
>>> +#define HDMI_REG_AFE_ISW_CTRL		0x63
>>> +
>>> +#define HDMI_REG_AFE_IP_CTRL		0x64
>>> +#define  AFE_IP_GAINBIT			BIT(7)
>>> +#define  AFE_IP_ER0			BIT(3)
>>> +#define  AFE_IP_RESETB			BIT(2)
>>> +
>>> +/* HDMI input data format registers */
>>> +#define HDMI_REG_INPUT_MODE		0x70
>>> +#define  IN_RGB				0x00
>>> +
>>> +/* HDMI general control registers */
>>> +#define HDMI_REG_HDMI_MODE		0xc0
>>> +#define  TX_HDMI_MODE			BIT(0)
>>> +
>>> +#define HDMI_REG_GCP			0xc1
>>> +#define  AVMUTE				BIT(0)
>>> +#define  HDMI_COLOR_DEPTH		GENMASK(6, 4)
>>> +#define  HDMI_COLOR_DEPTH_24		FIELD_PREP(HDMI_COLOR_DEPTH, 4)
>>> +
>>> +#define HDMI_REG_PKT_GENERAL_CTRL	0xc6
>>> +#define  ENABLE_PKT			BIT(0)
>>> +#define  REPEAT_PKT			BIT(1)
>>> +
>>> +/*
>>> +---------------------------------------------------------------------
>>> +--
>>> +------
>>> + * 3) HDMI register bank1: 0x130 ~ 0x1ff (HDMI packet registers)  */
>>> +
>>> +/* AVI packet registers */
>>> +#define HDMI_REG_AVI_DB1		0x158
>>> +#define  AVI_DB1_COLOR_SPACE		GENMASK(6, 5)
>>> +#define  AVI_COLOR_SPACE_RGB		FIELD_PREP(AVI_DB1_COLOR_SPACE, 0)
>>> +
>>> +#define MAX_PIXEL_CLOCK_KHZ		150000
>>> +#define HIGH_PIXEL_CLOCK_KHZ		80000
>>> +
>>> +struct it6263 {
>>> +	struct device *dev;
>>> +	struct i2c_client *hdmi_i2c;
>>> +	struct i2c_client *lvds_i2c;
>>> +	struct regmap *hdmi_regmap;
>>> +	struct regmap *lvds_regmap;
>>> +	struct drm_bridge bridge;
>>> +	struct drm_bridge *next_bridge;
>>> +	struct drm_connector connector;
>>> +	struct gpio_desc *reset_gpio;
>>> +	bool lvds_dual_link;
>>> +	bool lvds_link12_swap;
>>> +};
>>> +
>>> +static inline struct it6263 *bridge_to_it6263(struct drm_bridge
>>> +*bridge) {
>>> +	return container_of(bridge, struct it6263, bridge); }
>>> +
>>> +static inline struct it6263 *connector_to_it6263(struct drm_connector
>>> +*conn) {
>>> +	return container_of(conn, struct it6263, connector); }
>>> +
>>> +static bool it6263_hdmi_writeable_reg(struct device *dev, unsigned
>>> +int
>>> +reg) {
>>> +	switch (reg) {
>>> +	case HDMI_REG_SW_RST:
>>> +	case HDMI_REG_BANK_CTRL:
>>> +	case HDMI_REG_DDC_MASTER_CTRL:
>>> +	case HDMI_REG_DDC_HEADER:
>>> +	case HDMI_REG_DDC_REQOFF:
>>> +	case HDMI_REG_DDC_REQCOUNT:
>>> +	case HDMI_REG_DDC_EDIDSEG:
>>> +	case HDMI_REG_DDC_CMD:
>>> +	case HDMI_REG_LVDS_PORT:
>>> +	case HDMI_REG_LVDS_PORT_EN:
>>> +	case HDMI_REG_AFE_DRV_CTRL:
>>> +	case HDMI_REG_AFE_XP_CTRL:
>>> +	case HDMI_REG_AFE_ISW_CTRL:
>>> +	case HDMI_REG_AFE_IP_CTRL:
>>> +	case HDMI_REG_INPUT_MODE:
>>> +	case HDMI_REG_HDMI_MODE:
>>> +	case HDMI_REG_GCP:
>>> +	case HDMI_REG_PKT_GENERAL_CTRL:
>>> +	case HDMI_REG_AVI_DB1:
>>> +		return true;
>>> +	default:
>>> +		return false;
>>> +	}
>>> +}
>>> +
>>> +static bool it6263_hdmi_readable_reg(struct device *dev, unsigned int
>>> +reg) {
>>> +	if (it6263_hdmi_writeable_reg(dev, reg))
>>> +		return true;
>>> +
>>> +	switch (reg) {
>>> +	case HDMI_REG_SYS_STATUS:
>>> +	case HDMI_REG_DDC_STATUS:
>>> +	case HDMI_REG_DDC_READFIFO:
>>> +		return true;
>>> +	default:
>>> +		return false;
>>> +	}
>>> +}
>>> +
>>> +static bool it6263_hdmi_volatile_reg(struct device *dev, unsigned int
>>> +reg) {
>>> +	switch (reg) {
>>> +	case HDMI_REG_SW_RST:
>>> +	case HDMI_REG_SYS_STATUS:
>>> +	case HDMI_REG_DDC_STATUS:
>>> +	case HDMI_REG_DDC_READFIFO:
>>> +		return true;
>>> +	default:
>>> +		return false;
>>> +	}
>>> +}
>>> +
>>> +static const struct regmap_range_cfg it6263_hdmi_range_cfg = {
>>> +	.range_min = 0x00,
>>> +	.range_max = HDMI_REG_AVI_DB1,
>>> +	.selector_reg = HDMI_REG_BANK_CTRL,
>>> +	.selector_mask = REG_BANK_SEL,
>>> +	.selector_shift = 0,
>>> +	.window_start = 0x00,
>>> +	.window_len = 0x100,
>>> +};
>>> +
>>> +static const struct regmap_config it6263_hdmi_regmap_config = {
>>> +	.name = "it6263-hdmi",
>>> +	.reg_bits = 8,
>>> +	.val_bits = 8,
>>> +	.writeable_reg = it6263_hdmi_writeable_reg,
>>> +	.readable_reg = it6263_hdmi_readable_reg,
>>> +	.volatile_reg = it6263_hdmi_volatile_reg,
>>> +	.max_register = HDMI_REG_AVI_DB1,
>>> +	.ranges = &it6263_hdmi_range_cfg,
>>> +	.num_ranges = 1,
>>> +	.cache_type = REGCACHE_MAPLE,
>>> +};
>>> +
>>> +static bool it6263_lvds_writeable_reg(struct device *dev, unsigned
>>> +int
>>> +reg) {
>>> +	switch (reg) {
>>> +	case LVDS_REG_05:
>>> +	case LVDS_REG_0B:
>>> +	case LVDS_REG_2C:
>>> +	case LVDS_REG_3C:
>>> +	case LVDS_REG_3F:
>>> +	case LVDS_REG_47:
>>> +	case LVDS_REG_48:
>>> +	case LVDS_REG_4F:
>>> +	case LVDS_REG_52:
>>> +		return true;
>>> +	default:
>>> +		return false;
>>> +	}
>>> +}
>>> +
>>> +static bool it6263_lvds_readable_reg(struct device *dev, unsigned int
>>> +reg) {
>>> +	return it6263_lvds_writeable_reg(dev, reg); }
>>> +
>>> +static bool it6263_lvds_volatile_reg(struct device *dev, unsigned int
>>> +reg) {
>>> +	return reg == LVDS_REG_05;
>>> +}
>>> +
>>> +static const struct regmap_config it6263_lvds_regmap_config = {
>>> +	.name = "it6263-lvds",
>>> +	.reg_bits = 8,
>>> +	.val_bits = 8,
>>> +	.writeable_reg = it6263_lvds_writeable_reg,
>>> +	.readable_reg = it6263_lvds_readable_reg,
>>> +	.volatile_reg = it6263_lvds_volatile_reg,
>>> +	.max_register = LVDS_REG_52,
>>> +	.cache_type = REGCACHE_MAPLE,
>>> +};
>>> +
>>> +static const char * const it6263_supplies[] = {
>>> +	"ivdd", "ovdd", "txavcc18", "txavcc33", "pvcc1", "pvcc2",
>>> +	"avcc", "anvdd", "apvdd"
>>> +};
>>> +
>>> +static int it6263_parse_dt(struct it6263 *it) {
>>> +	struct device *dev = it->dev;
>>> +	struct device_node *port0, *port1;
>>> +	int ret = 0;
>>> +
>>> +	it->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 2, 0);
>>> +	if (IS_ERR(it->next_bridge))
>>> +		return dev_err_probe(dev, PTR_ERR(it->next_bridge),
>>> +				     "failed to get next bridge\n");
>>> +
>>> +	port0 = of_graph_get_port_by_id(dev->of_node, 0);
>>> +	port1 = of_graph_get_port_by_id(dev->of_node, 1);
>>> +	if (port0 && port1) {
>>> +		if (of_property_read_bool(port0, "dual-lvds-even-pixels") &&
>>> +		    of_property_read_bool(port1, "dual-lvds-odd-pixels")) {
>>> +			it->lvds_dual_link = true;
>>> +			it->lvds_link12_swap = true;
>>> +		} else if (of_property_read_bool(port0, "dual-lvds-odd-pixels") &&
>>> +			   of_property_read_bool(port1, "dual-lvds-even-pixels")) {
>>> +			it->lvds_dual_link = true;
>>> +		}
>>> +
>>> +		if (!it->lvds_dual_link) {
>>> +			dev_err(dev,
>>> +				"failed to get LVDS dual link pixel order\n");
>>> +			ret = -EINVAL;
>>> +		}
>>> +	} else if (port1) {
>>> +		ret = -EINVAL;
>>> +		dev_err(dev, "single input LVDS port1 is not supported\n");
>>
>> 		Are you supporting single input LVDS port0??
>>
>>> +	} else if (!port0) {
>>> +		ret = -EINVAL;
>>> +		dev_err(dev, "no input LVDS port\n");
>>> +	}
>>> +
>>> +	of_node_put(port0);
>>> +	of_node_put(port1);
>>> +
>>> +	return ret;
>>> +}
>>> +
>>> +static inline void it6263_reset(struct it6263 *it) {
>>> +	if (!it->reset_gpio)
>>> +		return;
>>> +
>>> +	gpiod_set_value_cansleep(it->reset_gpio, 0);
>>> +	fsleep(1000);
>>> +	gpiod_set_value_cansleep(it->reset_gpio, 1);
>>> +	/* The chip maker says the low pulse should be at least 40ms. */
>>> +	fsleep(40000);
>>> +	gpiod_set_value_cansleep(it->reset_gpio, 0);
>>> +	/* addtional time to wait the high voltage to be stable */
>>> +	fsleep(5000);
>>
>> What about other resets ??
>>
>> /* AFE PLL reset and  pclk reset */
>>
>>> +}
>>> +
>>> +static inline int it6263_lvds_set_i2c_addr(struct it6263 *it) {
>>> +	int ret;
>>> +
>>> +	ret = regmap_write(it->hdmi_regmap, HDMI_REG_LVDS_PORT,
>>> +			   LVDS_INPUT_CTRL_I2C_ADDR << 1);
>>> +	if (ret)
>>> +		return ret;
>>> +
>>> +	return regmap_write(it->hdmi_regmap, HDMI_REG_LVDS_PORT_EN, BIT(0));
>>> +}
>>> +
>>> +static inline void it6263_lvds_reset(struct it6263 *it) {
>>> +	/* AFE PLL reset */
>>> +	regmap_write_bits(it->lvds_regmap, LVDS_REG_3C, BIT(0), 0x0);
>>> +	fsleep(1000);
>>> +	regmap_write_bits(it->lvds_regmap, LVDS_REG_3C, BIT(0), BIT(0));
>>> +
>>> +	/* software pixel clock domain reset */
>>> +	regmap_write_bits(it->lvds_regmap, LVDS_REG_05, REG_SOFT_P_RST,
>>> +			  REG_SOFT_P_RST);
>>> +	fsleep(1000);
>>> +	regmap_write_bits(it->lvds_regmap, LVDS_REG_05, REG_SOFT_P_RST, 0x0);
>>> +	fsleep(10000);
>>> +}
>>> +
>>> +static inline void it6263_lvds_set_interface(struct it6263 *it) {
>>> +	/* color depth */
>>> +	regmap_write_bits(it->lvds_regmap, LVDS_REG_2C, REG_COL_DEP, BIT8);
>>> +	/* output mapping */
>>> +	regmap_write_bits(it->lvds_regmap, LVDS_REG_2C, OUT_MAP, JEIDA);
>>> +
>>> +	if (it->lvds_dual_link) {
>>> +		regmap_write_bits(it->lvds_regmap, LVDS_REG_2C, DMODE, DISO);
>>> +		regmap_write_bits(it->lvds_regmap, LVDS_REG_52, BIT(1), BIT(1));
>>> +	} else {
>>> +		regmap_write_bits(it->lvds_regmap, LVDS_REG_2C, DMODE, SISO);
>>> +		regmap_write_bits(it->lvds_regmap, LVDS_REG_52, BIT(1), 0);
>>> +	}
>>> +}
>>> +
>>> +static inline void it6263_lvds_set_afe(struct it6263 *it) {
>>> +	regmap_write(it->lvds_regmap, LVDS_REG_3C, 0xaa);
>>> +	regmap_write(it->lvds_regmap, LVDS_REG_3F, 0x02);
>>> +	regmap_write(it->lvds_regmap, LVDS_REG_47, 0xaa);
>>> +	regmap_write(it->lvds_regmap, LVDS_REG_48, 0x02);
>>> +	regmap_write(it->lvds_regmap, LVDS_REG_4F, 0x11);
>>> +
>>> +	regmap_write_bits(it->lvds_regmap, LVDS_REG_0B, REG_SSC_PCLK_RF,
>>> +			  REG_SSC_PCLK_RF);
>>> +	regmap_write_bits(it->lvds_regmap, LVDS_REG_3C, 0x07, 0);
>>> +	regmap_write_bits(it->lvds_regmap, LVDS_REG_2C, REG_DESSC_ENB,
>>> +			  REG_DESSC_ENB);
>>> +}
>>> +
>>> +static inline void it6263_lvds_sys_cfg(struct it6263 *it) {
>>> +	regmap_write_bits(it->lvds_regmap, LVDS_REG_0B, REG_LVDS_IN_SWAP,
>>> +			  it->lvds_link12_swap ? REG_LVDS_IN_SWAP : 0); }
>>> +
>>> +static inline void it6263_lvds_config(struct it6263 *it) {
>>> +	it6263_lvds_reset(it);
>>> +	it6263_lvds_set_interface(it);
>>> +	it6263_lvds_set_afe(it);
>>> +	it6263_lvds_sys_cfg(it);
>>> +}
>>> +
>>> +static inline void it6263_hdmi_config(struct it6263 *it) {
>>> +	regmap_write(it->hdmi_regmap, HDMI_REG_SW_RST, HDMI_RST_ALL);
>>> +	regmap_write(it->hdmi_regmap, HDMI_REG_INPUT_MODE, IN_RGB);
>>> +	regmap_write_bits(it->hdmi_regmap, HDMI_REG_GCP, HDMI_COLOR_DEPTH,
>>> +			  HDMI_COLOR_DEPTH_24);
>>> +	regmap_write_bits(it->hdmi_regmap, HDMI_REG_AVI_DB1,
>>> +			  AVI_DB1_COLOR_SPACE, AVI_COLOR_SPACE_RGB); }
>>> +
>>> +static enum drm_connector_status it6263_detect(struct it6263 *it) {
>>> +	unsigned int val;
>>> +
>>> +	regmap_read(it->hdmi_regmap, HDMI_REG_SYS_STATUS, &val);
>>> +	if (val & HPDETECT)
>>> +		return connector_status_connected;
>>> +	else
>>> +		return connector_status_disconnected; }
>>> +
>>> +static enum drm_connector_status
>>> +it6263_connector_detect(struct drm_connector *connector, bool force) {
>>> +	struct it6263 *it = connector_to_it6263(connector);
>>> +
>>> +	return it6263_detect(it);
>>> +}
>>> +
>>> +static const struct drm_connector_funcs it6263_connector_funcs = {
>>> +	.detect = it6263_connector_detect,
>>> +	.fill_modes = drm_helper_probe_single_connector_modes,
>>> +	.destroy = drm_connector_cleanup,
>>> +	.reset = drm_atomic_helper_connector_reset,
>>> +	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
>>> +	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
>>> +};
>>> +
>>> +static int it6263_read_edid(void *data, u8 *buf, unsigned int block,
>>> +size_t len) {
>>> +	struct it6263 *it = data;
>>> +	struct regmap *regmap = it->hdmi_regmap;
>>> +	unsigned int start = (block % 2) * EDID_LENGTH;
>>> +	unsigned int segment = block >> 1;
>>> +	unsigned int count, val;
>>> +	int ret;
>>> +
>>> +	regmap_write(regmap, HDMI_REG_DDC_MASTER_CTRL, MASTER_SEL_HOST);
>>> +	regmap_write(regmap, HDMI_REG_DDC_HEADER, DDC_ADDR << 1);
>>> +	regmap_write(regmap, HDMI_REG_DDC_EDIDSEG, segment);
>>> +
>>> +	while (len) {
>>> +		/* clear DDC FIFO */
>>> +		regmap_write(regmap, HDMI_REG_DDC_CMD, DDC_CMD_FIFO_CLR);
>>> +
>>> +		ret = regmap_read_poll_timeout(regmap, HDMI_REG_DDC_STATUS,
>>> +					       val, val & DDC_DONE,
>>> +					       2000, 10000);
>>> +		if (ret) {
>>> +			dev_err(it->dev, "failed to clear DDC FIFO:%d\n", ret);
>>> +			return ret;
>>> +		}
>>> +
>>> +		count = len > HDMI_DDC_FIFO_BYTES ? HDMI_DDC_FIFO_BYTES : len;
>>> +
>>> +		/* fire the read command */
>>> +		regmap_write(regmap, HDMI_REG_DDC_REQOFF, start);
>>> +		regmap_write(regmap, HDMI_REG_DDC_REQCOUNT, count);
>>> +		regmap_write(regmap, HDMI_REG_DDC_CMD, DDC_CMD_EDID_READ);
>>> +
>>> +		start += count;
>>> +		len -= count;
>>> +
>>> +		ret = regmap_read_poll_timeout(regmap, HDMI_REG_DDC_STATUS, val,
>>> +					       val & (DDC_DONE | DDC_ERROR),
>>> +					       20000, 250000);
>>> +		if (ret && !(val & DDC_ERROR)) {
>>> +			dev_err(it->dev, "failed to read EDID:%d\n", ret);
>>> +			return ret;
>>> +		}
>>> +
>>> +		if (val & DDC_ERROR) {
>>> +			dev_err(it->dev, "DDC error\n");
>>> +			return -EIO;
>>> +		}
>>> +
>>> +		/* cache to buffer */
>>> +		for (; count > 0; count--) {
>>> +			regmap_read(regmap, HDMI_REG_DDC_READFIFO, &val);
>>> +			*(buf++) = val;
>>> +		}
>>> +	}
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static int it6263_connector_get_modes(struct drm_connector
>>> +*connector) {
>>> +	struct it6263 *it = connector_to_it6263(connector);
>>> +	const struct drm_edid *drm_edid;
>>> +	int count;
>>> +
>>> +	drm_edid = drm_edid_read_custom(connector, it6263_read_edid, it);
>>> +
>>> +	drm_edid_connector_update(connector, drm_edid);
>>> +	count = drm_edid_connector_add_modes(connector);
>>> +
>>> +	drm_edid_free(drm_edid);
>>> +
>>> +	return count;
>>> +}
>>> +
>>> +static const struct drm_connector_helper_funcs it6263_connector_helper_funcs = {
>>> +	.get_modes = it6263_connector_get_modes, };
>>> +
>>> +static int it6263_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 *mode = &crtc_state->adjusted_mode;
>>> +
>>> +	return mode->clock > MAX_PIXEL_CLOCK_KHZ ? -EINVAL : 0; }
>>> +
>>> +static void
>>> +it6263_bridge_atomic_disable(struct drm_bridge *bridge,
>>> +			     struct drm_bridge_state *old_bridge_state) {
>>> +	struct it6263 *it = bridge_to_it6263(bridge);
>>> +
>>> +	regmap_write_bits(it->hdmi_regmap, HDMI_REG_GCP, AVMUTE, AVMUTE);
>>> +	regmap_write(it->hdmi_regmap, HDMI_REG_PKT_GENERAL_CTRL, 0);
>>> +	regmap_write(it->hdmi_regmap, HDMI_REG_AFE_DRV_CTRL,
>>> +		     AFE_DRV_RST | AFE_DRV_PWD);
>>> +}
>>> +
>>> +static void
>>> +it6263_bridge_atomic_enable(struct drm_bridge *bridge,
>>> +			    struct drm_bridge_state *old_bridge_state) {
>>> +	struct drm_atomic_state *state = old_bridge_state->base.state;
>>> +	struct it6263 *it = bridge_to_it6263(bridge);
>>> +	const struct drm_crtc_state *crtc_state;
>>> +	struct regmap *regmap = it->hdmi_regmap;
>>> +	const struct drm_display_mode *mode;
>>> +	struct drm_connector *connector;
>>> +	bool is_stable = false;
>>> +	struct drm_crtc *crtc;
>>> +	unsigned int val;
>>> +	bool pclk_high;
>>> +	int i, ret;
>>> +
>>> +	connector = drm_atomic_get_new_connector_for_encoder(state,
>>> +							     bridge->encoder);
>>> +	crtc = drm_atomic_get_new_connector_state(state, connector)->crtc;
>>> +	crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
>>> +	mode = &crtc_state->adjusted_mode;
>>> +
>>> +	regmap_write(regmap, HDMI_REG_HDMI_MODE, TX_HDMI_MODE);
>>> +
>>> +	/* HDMI AFE setup */
>>> +	pclk_high = mode->clock > HIGH_PIXEL_CLOCK_KHZ ? true : false;
>>> +	regmap_write(regmap, HDMI_REG_AFE_DRV_CTRL, AFE_DRV_RST);
>>> +	if (pclk_high)
>>> +		regmap_write(regmap, HDMI_REG_AFE_XP_CTRL,
>>> +			     AFE_XP_GAINBIT | AFE_XP_RESETB);
>>> +	else
>>> +		regmap_write(regmap, HDMI_REG_AFE_XP_CTRL,
>>> +			     AFE_XP_ER0 | AFE_XP_RESETB);
>>> +	regmap_write(regmap, HDMI_REG_AFE_ISW_CTRL, 0x10);
>>> +	if (pclk_high)
>>> +		regmap_write(regmap, HDMI_REG_AFE_IP_CTRL,
>>> +			     AFE_IP_GAINBIT | AFE_IP_RESETB);
>>> +	else
>>> +		regmap_write(regmap, HDMI_REG_AFE_IP_CTRL,
>>> +			     AFE_IP_ER0 | AFE_IP_RESETB);
>>> +
>>> +	/* HDMI software video reset */
>>> +	regmap_write_bits(regmap, HDMI_REG_SW_RST, SOFTV_RST, SOFTV_RST);
>>> +	fsleep(1000);
>>> +	regmap_write_bits(regmap, HDMI_REG_SW_RST, SOFTV_RST, 0);
>>> +
>>> +	/* reconfigure LVDS and retry several times in case video is instable */
>>> +	for (i = 0; i < 3; i++) {
>>> +		ret = regmap_read_poll_timeout(regmap, HDMI_REG_SYS_STATUS, val,
>>> +					       val & TXVIDSTABLE,
>>> +					       20000, 500000);
>>> +		if (!ret) {
>>> +			is_stable = true;
>>> +			break;
>>> +		}
>>> +
>>> +		it6263_lvds_config(it);
>>> +	}
>>> +
>>> +	if (!is_stable)
>>> +		dev_warn(it->dev, "failed to wait for video stable\n");
>>> +
>>> +	/* HDMI AFE reset release and power up */
>>> +	regmap_write(regmap, HDMI_REG_AFE_DRV_CTRL, 0);
>>> +
>>> +	regmap_write_bits(regmap, HDMI_REG_GCP, AVMUTE, 0);
>>> +
>>> +	regmap_write(regmap, HDMI_REG_PKT_GENERAL_CTRL, ENABLE_PKT |
>>> +REPEAT_PKT); }
>>> +
>>> +static enum drm_mode_status
>>> +it6263_bridge_mode_valid(struct drm_bridge *bridge,
>>> +			 const struct drm_display_info *info,
>>> +			 const struct drm_display_mode *mode) {
>>> +	return mode->clock > MAX_PIXEL_CLOCK_KHZ ? MODE_CLOCK_HIGH :
>>> +MODE_OK; }
>>> +
>>> +static int it6263_bridge_attach(struct drm_bridge *bridge,
>>> +				enum drm_bridge_attach_flags flags) {
>>> +	struct it6263 *it = bridge_to_it6263(bridge);
>>> +	int ret;
>>> +
>>> +	ret = drm_bridge_attach(bridge->encoder, it->next_bridge, bridge,
>>> +				flags | DRM_BRIDGE_ATTACH_NO_CONNECTOR);
>>> +	if (ret < 0)
>>> +		return ret;
>>> +
>>> +	if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
>>> +		return 0;
>>> +
>>> +	it->connector.polled = DRM_CONNECTOR_POLL_CONNECT |
>>> +			       DRM_CONNECTOR_POLL_DISCONNECT;
>>> +
>>> +	ret = drm_connector_init(bridge->dev, &it->connector,
>>> +				 &it6263_connector_funcs,
>>> +				 DRM_MODE_CONNECTOR_HDMIA);
>>> +	if (ret)
>>> +		return ret;
>>> +
>>> +	drm_connector_helper_add(&it->connector,
>>> +				 &it6263_connector_helper_funcs);
>>> +	drm_connector_attach_encoder(&it->connector, bridge->encoder);
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static enum drm_connector_status it6263_bridge_detect(struct
>>> +drm_bridge
>>> +*bridge) {
>>> +	struct it6263 *it = bridge_to_it6263(bridge);
>>> +
>>> +	return it6263_detect(it);
>>> +}
>>> +
>>> +static const struct drm_edid *
>>> +it6263_bridge_edid_read(struct drm_bridge *bridge,
>>> +			struct drm_connector *connector)
>>> +{
>>> +	struct it6263 *it = bridge_to_it6263(bridge);
>>> +
>>> +	return drm_edid_read_custom(connector, it6263_read_edid, it); }
>>> +
>>> +static u32 *
>>> +it6263_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
>>> +					struct drm_bridge_state *bridge_state,
>>> +					struct drm_crtc_state *crtc_state,
>>> +					struct drm_connector_state *conn_state,
>>> +					u32 output_fmt,
>>> +					unsigned int *num_input_fmts)
>>> +{
>>> +	u32 *input_fmts;
>>> +
>>> +	input_fmts = kmalloc(sizeof(*input_fmts), GFP_KERNEL);
>>> +	if (!input_fmts) {
>>> +		*num_input_fmts = 0;
>>> +		return NULL;
>>> +	}
>>> +
>>> +	input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA;
>>
>> Why is it hardcoded? What about supporting VESA??
>>
>>> +	*num_input_fmts = 1;
>>> +
>>> +	return input_fmts;
>>> +}
>>> +
>>> +static const struct drm_bridge_funcs it6263_bridge_funcs = {
>>> +	.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,
>>> +	.attach = it6263_bridge_attach,
>>> +	.mode_valid = it6263_bridge_mode_valid,
>>> +	.atomic_disable = it6263_bridge_atomic_disable,
>>> +	.atomic_enable = it6263_bridge_atomic_enable,
>>> +	.atomic_check = it6263_bridge_atomic_check,
>>> +	.detect = it6263_bridge_detect,
>>> +	.edid_read = it6263_bridge_edid_read,
>>> +	.atomic_get_input_bus_fmts =
>>> +it6263_bridge_atomic_get_input_bus_fmts,
>>> +};
> 
> Like [1]
> static const struct drm_bridge_funcs it6263_bridge_funcs = {
> 	.attach = it6263_bridge_attach,
> 	.mode_set = it6263_bridge_mode_set,
> 	.disable = it6263_bridge_disable,
> 	.enable = it6263_bridge_enable,
> 	.get_edid = it6263_bridge_get_edid,
> 	.detect = it6263_bridge_detect,
> };
> 
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c?h=v6.12-rc1#n998
> 
> Is it not sufficient for your use case??

If we decide to document the LVDS data mapping in dt-binding,
then it is practically ok to use the non-atomic callbacks like
the adv7511 driver, otherwise, the atomic callbacks are required
due to the bus format negotiation.

> 
> Cheers,
> Biju
> 
>>> +
>>> +static int it6263_probe(struct i2c_client *client) {
>>> +	struct device *dev = &client->dev;
>>> +	struct it6263 *it;
>>> +	int ret;
>>> +
>>> +	it = devm_kzalloc(dev, sizeof(*it), GFP_KERNEL);
>>> +	if (!it)
>>> +		return -ENOMEM;
>>> +
>>> +	it->dev = dev;
>>> +	it->hdmi_i2c = client;
>>> +
>>> +	it->hdmi_regmap = devm_regmap_init_i2c(client,
>>> +					       &it6263_hdmi_regmap_config);
>>> +	if (IS_ERR(it->hdmi_regmap))
>>> +		return dev_err_probe(dev, PTR_ERR(it->hdmi_regmap),
>>> +				     "failed to init I2C regmap for HDMI\n");
>>> +
>>> +	it->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
>>> +	if (IS_ERR(it->reset_gpio))
>>> +		return dev_err_probe(dev, PTR_ERR(it->reset_gpio),
>>> +				     "failed to get reset gpio\n");
>>> +
>>> +	ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(it6263_supplies),
>>> +					     it6263_supplies);
>>> +	if (ret)
>>> +		return dev_err_probe(dev, ret, "failed to get power supplies\n");
>>> +
>>> +	ret = it6263_parse_dt(it);
>>> +	if (ret)
>>> +		return ret;
>>> +
>>> +	it6263_reset(it);
>>> +
>>> +	ret = it6263_lvds_set_i2c_addr(it);
>>> +	if (ret)
>>> +		return dev_err_probe(dev, ret, "failed to set I2C addr\n");
>>> +
>>> +	it->lvds_i2c = devm_i2c_new_dummy_device(dev, client->adapter,
>>> +						 LVDS_INPUT_CTRL_I2C_ADDR);
>>> +	if (IS_ERR(it->lvds_i2c))
>>> +		dev_err_probe(it->dev, PTR_ERR(it->lvds_i2c),
>>> +			      "failed to allocate I2C device for LVDS\n");
>>
>> Maybe use action_or_reset and call i2c_unregister_device();
>>
>>> +
>>> +	it->lvds_regmap = devm_regmap_init_i2c(it->lvds_i2c,
>>> +					       &it6263_lvds_regmap_config);
>>> +	if (IS_ERR(it->lvds_regmap))
>>> +		return dev_err_probe(dev, PTR_ERR(it->lvds_regmap),
>>> +				     "failed to init I2C regmap for LVDS\n");
>>
>>> +
>>> +	it6263_lvds_config(it);
>>> +	it6263_hdmi_config(it);
>>
>>> +
>>> +	i2c_set_clientdata(client, it);
>>> +
>>> +	it->bridge.funcs = &it6263_bridge_funcs;
>>> +	it->bridge.of_node = dev->of_node;
>>> +	it->bridge.ops = DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_DETECT;
>>
>> 	it->bridge.type = DRM_MODE_CONNECTOR_HDMIA; ??
>>
>>> +	drm_bridge_add(&it->bridge);
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static void it6263_remove(struct i2c_client *client) {
>>> +	struct it6263 *it = i2c_get_clientdata(client);
>>> +
>>> +	drm_bridge_remove(&it->bridge);
>>
>>> +}
>>> +
>>> +static const struct of_device_id it6263_of_match[] = {
>>> +	{ .compatible = "ite,it6263", },
>>> +	{ }
>>> +};
>>> +MODULE_DEVICE_TABLE(of, it6263_of_match);
>>> +
>>> +static const struct i2c_device_id it6263_i2c_ids[] = {
>>> +	{ "it6263", 0 },
>>> +	{ }
>>> +};
>>> +MODULE_DEVICE_TABLE(i2c, it6263_i2c_ids);
>>> +
>>> +static struct i2c_driver it6263_driver = {
>>> +	.probe = it6263_probe,
>>> +	.remove = it6263_remove,
>>> +	.driver = {
>>> +		.name = "it6263",
>>> +		.of_match_table = it6263_of_match,
>>> +	},
>>> +	.id_table = it6263_i2c_ids,
>>> +};
>>> +module_i2c_driver(it6263_driver);
>>> +
>>> +MODULE_DESCRIPTION("ITE Tech. Inc. IT6263 LVDS/HDMI bridge");
>>> +MODULE_AUTHOR("Liu Ying <victor.liu@nxp.com>");
>>> +MODULE_LICENSE("GPL");
>>> --
>>> 2.34.1
>>>
> 

-- 
Regards,
Liu Ying


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

* Re: [PATCH 6/8] drm/bridge: Add ITE IT6263 LVDS to HDMI converter
  2024-10-09  8:33       ` Liu Ying
@ 2024-10-09 17:02         ` Dmitry Baryshkov
  0 siblings, 0 replies; 38+ messages in thread
From: Dmitry Baryshkov @ 2024-10-09 17:02 UTC (permalink / raw)
  To: Liu Ying
  Cc: Biju Das, dri-devel@lists.freedesktop.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linux-arm-kernel@lists.infradead.org,
	andrzej.hajda@intel.com, neil.armstrong@linaro.org,
	rfoss@kernel.org, laurent.pinchart, jonas@kwiboo.se,
	jernej.skrabec@gmail.com, maarten.lankhorst@linux.intel.com,
	mripard@kernel.org, tzimmermann@suse.de, airlied@gmail.com,
	simona@ffwll.ch, robh@kernel.org, krzk+dt@kernel.org,
	conor+dt@kernel.org, shawnguo@kernel.org, s.hauer@pengutronix.de,
	kernel@pengutronix.de, festevam@gmail.com,
	catalin.marinas@arm.com, will@kernel.org,
	quic_bjorande@quicinc.com, geert+renesas@glider.be, arnd@arndb.de,
	nfraprado@collabora.com, o.rempel@pengutronix.de,
	y.moog@phytec.de

On Wed, 9 Oct 2024 at 11:32, Liu Ying <victor.liu@nxp.com> wrote:
>
> On 09/30/2024, Biju Das wrote:
> > Hi Liu,
>
> Hi Biju,
>
> >
> >> -----Original Message-----
> >> From: Biju Das
> >> Sent: Monday, September 30, 2024 10:16 AM
> >> Subject: RE: [PATCH 6/8] drm/bridge: Add ITE IT6263 LVDS to HDMI converter
> >>
> >> Hi Liu,
> >>
> >> Thanks for the patch.
> >>
> >>> -----Original Message-----
> >>> From: linux-arm-kernel <linux-arm-kernel-bounces@lists.infradead.org>
> >>> On Behalf Of Liu Ying
> >>> Sent: Monday, September 30, 2024 6:29 AM
> >>> Subject: [PATCH 6/8] drm/bridge: Add ITE IT6263 LVDS to HDMI converter
> >>>
> >>> Add basic HDMI video output support. Currently, only RGB888 output
> >>> pixel format is supported.  At the LVDS input side, the driver
> >>> supports single LVDS link and dual LVDS links with "jeida-24" LVDS mapping.
> >>>
> >>> Product link:
> >>> https://www.ite.com.tw/en/product/cate1/IT6263
> >>>
> >>> Signed-off-by: Liu Ying <victor.liu@nxp.com>
> >>> ---
> >>>  drivers/gpu/drm/bridge/Kconfig      |   8 +
> >>>  drivers/gpu/drm/bridge/Makefile     |   1 +
> >>>  drivers/gpu/drm/bridge/ite-it6263.c | 829
> >>> ++++++++++++++++++++++++++++
> >>>  3 files changed, 838 insertions(+)
> >>>  create mode 100644 drivers/gpu/drm/bridge/ite-it6263.c
> >>>
> >>> diff --git a/drivers/gpu/drm/bridge/Kconfig
> >>> b/drivers/gpu/drm/bridge/Kconfig index
> >>> 3eb955333c80..93f99682a090 100644
> >>> --- a/drivers/gpu/drm/bridge/Kconfig
> >>> +++ b/drivers/gpu/drm/bridge/Kconfig
> >>> @@ -90,6 +90,14 @@ config DRM_FSL_LDB
> >>>     help
> >>>       Support for i.MX8MP DPI-to-LVDS on-SoC encoder.
> >>>
> >>> +config DRM_ITE_IT6263
> >>> +   tristate "ITE IT6263 LVDS/HDMI bridge"
> >>> +   depends on OF
> >>> +   select DRM_KMS_HELPER
> >>> +   select REGMAP_I2C
> >>> +   help
> >>> +     ITE IT6263 LVDS to HDMI bridge chip driver.
> >>> +
> >>>  config DRM_ITE_IT6505
> >>>     tristate "ITE IT6505 DisplayPort bridge"
> >>>     depends on OF
> >>> diff --git a/drivers/gpu/drm/bridge/Makefile
> >>> b/drivers/gpu/drm/bridge/Makefile index 7df87b582dca..f3776dd473fd
> >>> 100644
> >>> --- a/drivers/gpu/drm/bridge/Makefile
> >>> +++ b/drivers/gpu/drm/bridge/Makefile
> >>> @@ -6,6 +6,7 @@ obj-$(CONFIG_DRM_CHRONTEL_CH7033) += chrontel-ch7033.o
> >>>  obj-$(CONFIG_DRM_CROS_EC_ANX7688) += cros-ec-anx7688.o
> >>>  obj-$(CONFIG_DRM_DISPLAY_CONNECTOR) += display-connector.o
> >>>  obj-$(CONFIG_DRM_FSL_LDB) += fsl-ldb.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
> >>>  obj-$(CONFIG_DRM_LONTIUM_LT9211) += lontium-lt9211.o diff --git
> >>> a/drivers/gpu/drm/bridge/ite-it6263.c
> >>> b/drivers/gpu/drm/bridge/ite-it6263.c
> >>> new file mode 100644
> >>> index 000000000000..886588497bc1
> >>> --- /dev/null
> >>> +++ b/drivers/gpu/drm/bridge/ite-it6263.c
> >>> @@ -0,0 +1,829 @@
> >>> +// SPDX-License-Identifier: GPL-2.0
> >>> +/*
> >>> + * Copyright 2024 NXP
> >>> + */
> >>> +
> >>> +#include <linux/bitfield.h>
> >>> +#include <linux/bits.h>
> >>> +#include <linux/delay.h>
> >>> +#include <linux/gpio/consumer.h>
> >>> +#include <linux/i2c.h>
> >>> +#include <linux/media-bus-format.h>
> >>> +#include <linux/module.h>
> >>> +#include <linux/of.h>
> >>> +#include <linux/regmap.h>
> >>> +#include <linux/regulator/consumer.h>
> >>> +
> >>> +#include <drm/drm_atomic.h>
> >>> +#include <drm/drm_atomic_helper.h>
> >>> +#include <drm/drm_atomic_state_helper.h> #include <drm/drm_bridge.h>
> >>> +#include <drm/drm_connector.h> #include <drm/drm_crtc.h> #include
> >>> +<drm/drm_edid.h> #include <drm/drm_of.h> #include
> >>> +<drm/drm_probe_helper.h>
> >>> +
> >>> +/*
> >>> +---------------------------------------------------------------------
> >>> +--
> >>> +------
> >>> + * LVDS registers
> >>> + */
> >>> +
> >>> +/* LVDS software reset registers */
> >>> +#define LVDS_REG_05                        0x05
> >>> +#define  REG_SOFT_P_RST                    BIT(1)
> >>> +
> >>> +/* LVDS system configuration registers */
> >>> +/* 0x0b */
> >>> +#define LVDS_REG_0B                        0x0b
> >>> +#define  REG_SSC_PCLK_RF           BIT(0)
> >>> +#define  REG_LVDS_IN_SWAP          BIT(1)
> >>> +
> >>> +/* LVDS test pattern gen control registers */
> >>> +/* 0x2c */
> >>> +#define LVDS_REG_2C                        0x2c
> >>> +#define  REG_COL_DEP                       GENMASK(1, 0)
> >>> +#define  BIT8                              FIELD_PREP(REG_COL_DEP, 2)
> >>> +#define  OUT_MAP                   BIT(4)
> >>> +#define  JEIDA                             0
> >>> +#define  REG_DESSC_ENB                     BIT(6)
> >>> +#define  DMODE                             BIT(7)
> >>> +#define  DISO                              BIT(7)
> >>> +#define  SISO                              0
> >>> +
> >>> +#define LVDS_REG_3C                        0x3c
> >>> +#define LVDS_REG_3F                        0x3f
> >>> +#define LVDS_REG_47                        0x47
> >>> +#define LVDS_REG_48                        0x48
> >>> +#define LVDS_REG_4F                        0x4f
> >>> +#define LVDS_REG_52                        0x52
> >>> +
> >>> +/*
> >>> +---------------------------------------------------------------------
> >>> +--
> >>> +------
> >>> + * HDMI registers are separated into three banks:
> >>> + * 1) HDMI register common bank: 0x00 ~ 0x2f  */
> >>> +
> >>> +/* HDMI genernal registers */
> >>> +#define HDMI_REG_SW_RST                    0x04
> >>> +#define  SOFTREF_RST                       BIT(5)
> >>> +#define  SOFTA_RST                 BIT(4)
> >>> +#define  SOFTV_RST                 BIT(3)
> >>> +#define  AUD_RST                   BIT(2)
> >>> +#define  HDCP_RST                  BIT(0)
> >>> +#define  HDMI_RST_ALL                      (SOFTREF_RST | SOFTA_RST | SOFTV_RST | \
> >>> +                                    AUD_RST | HDCP_RST)
> >>> +
> >>> +#define HDMI_REG_SYS_STATUS                0x0e
> >>> +#define  HPDETECT                  BIT(6)
> >>> +#define  TXVIDSTABLE                       BIT(4)
> >>> +
> >>> +#define HDMI_REG_BANK_CTRL         0x0f
> >>> +#define  REG_BANK_SEL                      BIT(0)
> >>> +
> >>> +/* HDMI System DDC control registers */
> >>> +#define HDMI_REG_DDC_MASTER_CTRL   0x10
> >>> +#define  MASTER_SEL_HOST           BIT(0)
> >>> +
> >>> +#define HDMI_REG_DDC_HEADER                0x11
> >>> +
> >>> +#define HDMI_REG_DDC_REQOFF                0x12
> >>> +#define HDMI_REG_DDC_REQCOUNT              0x13
> >>> +#define HDMI_REG_DDC_EDIDSEG               0x14
> >>> +
> >>> +#define HDMI_REG_DDC_CMD           0x15
> >>> +#define  DDC_CMD_EDID_READ         0x3
> >>> +#define  DDC_CMD_FIFO_CLR          0x9
> >>> +
> >>> +#define HDMI_REG_DDC_STATUS                0x16
> >>> +#define  DDC_DONE                  BIT(7)
> >>> +#define  DDC_NOACK                 BIT(5)
> >>> +#define  DDC_WAITBUS                       BIT(4)
> >>> +#define  DDC_ARBILOSE                      BIT(3)
> >>> +#define  DDC_ERROR                 (DDC_NOACK | DDC_WAITBUS | DDC_ARBILOSE)
> >>> +
> >>> +#define HDMI_DDC_FIFO_BYTES                32
> >>> +#define HDMI_REG_DDC_READFIFO              0x17
> >>> +#define HDMI_REG_LVDS_PORT         0x1d /* LVDS input control I2C addr */
> >>> +#define HDMI_REG_LVDS_PORT_EN              0x1e
> >>> +#define LVDS_INPUT_CTRL_I2C_ADDR   0x33
> >>> +
> >>> +/*
> >>> +---------------------------------------------------------------------
> >>> +--
> >>> +------
> >>> + * 2) HDMI register bank0: 0x30 ~ 0xff  */
> >>> +
> >>> +/* HDMI AFE registers */
> >>> +#define HDMI_REG_AFE_DRV_CTRL              0x61
> >>> +#define  AFE_DRV_PWD                       BIT(5)
> >>> +#define  AFE_DRV_RST                       BIT(4)
> >>> +
> >>> +#define HDMI_REG_AFE_XP_CTRL               0x62
> >>> +#define  AFE_XP_GAINBIT                    BIT(7)
> >>> +#define  AFE_XP_ER0                        BIT(4)
> >>> +#define  AFE_XP_RESETB                     BIT(3)
> >>> +
> >>> +#define HDMI_REG_AFE_ISW_CTRL              0x63
> >>> +
> >>> +#define HDMI_REG_AFE_IP_CTRL               0x64
> >>> +#define  AFE_IP_GAINBIT                    BIT(7)
> >>> +#define  AFE_IP_ER0                        BIT(3)
> >>> +#define  AFE_IP_RESETB                     BIT(2)
> >>> +
> >>> +/* HDMI input data format registers */
> >>> +#define HDMI_REG_INPUT_MODE                0x70
> >>> +#define  IN_RGB                            0x00
> >>> +
> >>> +/* HDMI general control registers */
> >>> +#define HDMI_REG_HDMI_MODE         0xc0
> >>> +#define  TX_HDMI_MODE                      BIT(0)
> >>> +
> >>> +#define HDMI_REG_GCP                       0xc1
> >>> +#define  AVMUTE                            BIT(0)
> >>> +#define  HDMI_COLOR_DEPTH          GENMASK(6, 4)
> >>> +#define  HDMI_COLOR_DEPTH_24               FIELD_PREP(HDMI_COLOR_DEPTH, 4)
> >>> +
> >>> +#define HDMI_REG_PKT_GENERAL_CTRL  0xc6
> >>> +#define  ENABLE_PKT                        BIT(0)
> >>> +#define  REPEAT_PKT                        BIT(1)
> >>> +
> >>> +/*
> >>> +---------------------------------------------------------------------
> >>> +--
> >>> +------
> >>> + * 3) HDMI register bank1: 0x130 ~ 0x1ff (HDMI packet registers)  */
> >>> +
> >>> +/* AVI packet registers */
> >>> +#define HDMI_REG_AVI_DB1           0x158
> >>> +#define  AVI_DB1_COLOR_SPACE               GENMASK(6, 5)
> >>> +#define  AVI_COLOR_SPACE_RGB               FIELD_PREP(AVI_DB1_COLOR_SPACE, 0)
> >>> +
> >>> +#define MAX_PIXEL_CLOCK_KHZ                150000
> >>> +#define HIGH_PIXEL_CLOCK_KHZ               80000
> >>> +
> >>> +struct it6263 {
> >>> +   struct device *dev;
> >>> +   struct i2c_client *hdmi_i2c;
> >>> +   struct i2c_client *lvds_i2c;
> >>> +   struct regmap *hdmi_regmap;
> >>> +   struct regmap *lvds_regmap;
> >>> +   struct drm_bridge bridge;
> >>> +   struct drm_bridge *next_bridge;
> >>> +   struct drm_connector connector;
> >>> +   struct gpio_desc *reset_gpio;
> >>> +   bool lvds_dual_link;
> >>> +   bool lvds_link12_swap;
> >>> +};
> >>> +
> >>> +static inline struct it6263 *bridge_to_it6263(struct drm_bridge
> >>> +*bridge) {
> >>> +   return container_of(bridge, struct it6263, bridge); }
> >>> +
> >>> +static inline struct it6263 *connector_to_it6263(struct drm_connector
> >>> +*conn) {
> >>> +   return container_of(conn, struct it6263, connector); }
> >>> +
> >>> +static bool it6263_hdmi_writeable_reg(struct device *dev, unsigned
> >>> +int
> >>> +reg) {
> >>> +   switch (reg) {
> >>> +   case HDMI_REG_SW_RST:
> >>> +   case HDMI_REG_BANK_CTRL:
> >>> +   case HDMI_REG_DDC_MASTER_CTRL:
> >>> +   case HDMI_REG_DDC_HEADER:
> >>> +   case HDMI_REG_DDC_REQOFF:
> >>> +   case HDMI_REG_DDC_REQCOUNT:
> >>> +   case HDMI_REG_DDC_EDIDSEG:
> >>> +   case HDMI_REG_DDC_CMD:
> >>> +   case HDMI_REG_LVDS_PORT:
> >>> +   case HDMI_REG_LVDS_PORT_EN:
> >>> +   case HDMI_REG_AFE_DRV_CTRL:
> >>> +   case HDMI_REG_AFE_XP_CTRL:
> >>> +   case HDMI_REG_AFE_ISW_CTRL:
> >>> +   case HDMI_REG_AFE_IP_CTRL:
> >>> +   case HDMI_REG_INPUT_MODE:
> >>> +   case HDMI_REG_HDMI_MODE:
> >>> +   case HDMI_REG_GCP:
> >>> +   case HDMI_REG_PKT_GENERAL_CTRL:
> >>> +   case HDMI_REG_AVI_DB1:
> >>> +           return true;
> >>> +   default:
> >>> +           return false;
> >>> +   }
> >>> +}
> >>> +
> >>> +static bool it6263_hdmi_readable_reg(struct device *dev, unsigned int
> >>> +reg) {
> >>> +   if (it6263_hdmi_writeable_reg(dev, reg))
> >>> +           return true;
> >>> +
> >>> +   switch (reg) {
> >>> +   case HDMI_REG_SYS_STATUS:
> >>> +   case HDMI_REG_DDC_STATUS:
> >>> +   case HDMI_REG_DDC_READFIFO:
> >>> +           return true;
> >>> +   default:
> >>> +           return false;
> >>> +   }
> >>> +}
> >>> +
> >>> +static bool it6263_hdmi_volatile_reg(struct device *dev, unsigned int
> >>> +reg) {
> >>> +   switch (reg) {
> >>> +   case HDMI_REG_SW_RST:
> >>> +   case HDMI_REG_SYS_STATUS:
> >>> +   case HDMI_REG_DDC_STATUS:
> >>> +   case HDMI_REG_DDC_READFIFO:
> >>> +           return true;
> >>> +   default:
> >>> +           return false;
> >>> +   }
> >>> +}
> >>> +
> >>> +static const struct regmap_range_cfg it6263_hdmi_range_cfg = {
> >>> +   .range_min = 0x00,
> >>> +   .range_max = HDMI_REG_AVI_DB1,
> >>> +   .selector_reg = HDMI_REG_BANK_CTRL,
> >>> +   .selector_mask = REG_BANK_SEL,
> >>> +   .selector_shift = 0,
> >>> +   .window_start = 0x00,
> >>> +   .window_len = 0x100,
> >>> +};
> >>> +
> >>> +static const struct regmap_config it6263_hdmi_regmap_config = {
> >>> +   .name = "it6263-hdmi",
> >>> +   .reg_bits = 8,
> >>> +   .val_bits = 8,
> >>> +   .writeable_reg = it6263_hdmi_writeable_reg,
> >>> +   .readable_reg = it6263_hdmi_readable_reg,
> >>> +   .volatile_reg = it6263_hdmi_volatile_reg,
> >>> +   .max_register = HDMI_REG_AVI_DB1,
> >>> +   .ranges = &it6263_hdmi_range_cfg,
> >>> +   .num_ranges = 1,
> >>> +   .cache_type = REGCACHE_MAPLE,
> >>> +};
> >>> +
> >>> +static bool it6263_lvds_writeable_reg(struct device *dev, unsigned
> >>> +int
> >>> +reg) {
> >>> +   switch (reg) {
> >>> +   case LVDS_REG_05:
> >>> +   case LVDS_REG_0B:
> >>> +   case LVDS_REG_2C:
> >>> +   case LVDS_REG_3C:
> >>> +   case LVDS_REG_3F:
> >>> +   case LVDS_REG_47:
> >>> +   case LVDS_REG_48:
> >>> +   case LVDS_REG_4F:
> >>> +   case LVDS_REG_52:
> >>> +           return true;
> >>> +   default:
> >>> +           return false;
> >>> +   }
> >>> +}
> >>> +
> >>> +static bool it6263_lvds_readable_reg(struct device *dev, unsigned int
> >>> +reg) {
> >>> +   return it6263_lvds_writeable_reg(dev, reg); }
> >>> +
> >>> +static bool it6263_lvds_volatile_reg(struct device *dev, unsigned int
> >>> +reg) {
> >>> +   return reg == LVDS_REG_05;
> >>> +}
> >>> +
> >>> +static const struct regmap_config it6263_lvds_regmap_config = {
> >>> +   .name = "it6263-lvds",
> >>> +   .reg_bits = 8,
> >>> +   .val_bits = 8,
> >>> +   .writeable_reg = it6263_lvds_writeable_reg,
> >>> +   .readable_reg = it6263_lvds_readable_reg,
> >>> +   .volatile_reg = it6263_lvds_volatile_reg,
> >>> +   .max_register = LVDS_REG_52,
> >>> +   .cache_type = REGCACHE_MAPLE,
> >>> +};
> >>> +
> >>> +static const char * const it6263_supplies[] = {
> >>> +   "ivdd", "ovdd", "txavcc18", "txavcc33", "pvcc1", "pvcc2",
> >>> +   "avcc", "anvdd", "apvdd"
> >>> +};
> >>> +
> >>> +static int it6263_parse_dt(struct it6263 *it) {
> >>> +   struct device *dev = it->dev;
> >>> +   struct device_node *port0, *port1;
> >>> +   int ret = 0;
> >>> +
> >>> +   it->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 2, 0);
> >>> +   if (IS_ERR(it->next_bridge))
> >>> +           return dev_err_probe(dev, PTR_ERR(it->next_bridge),
> >>> +                                "failed to get next bridge\n");
> >>> +
> >>> +   port0 = of_graph_get_port_by_id(dev->of_node, 0);
> >>> +   port1 = of_graph_get_port_by_id(dev->of_node, 1);
> >>> +   if (port0 && port1) {
> >>> +           if (of_property_read_bool(port0, "dual-lvds-even-pixels") &&
> >>> +               of_property_read_bool(port1, "dual-lvds-odd-pixels")) {
> >>> +                   it->lvds_dual_link = true;
> >>> +                   it->lvds_link12_swap = true;
> >>> +           } else if (of_property_read_bool(port0, "dual-lvds-odd-pixels") &&
> >>> +                      of_property_read_bool(port1, "dual-lvds-even-pixels")) {
> >>> +                   it->lvds_dual_link = true;
> >>> +           }
> >>> +
> >>> +           if (!it->lvds_dual_link) {
> >>> +                   dev_err(dev,
> >>> +                           "failed to get LVDS dual link pixel order\n");
> >>> +                   ret = -EINVAL;
> >>> +           }
> >>> +   } else if (port1) {
> >>> +           ret = -EINVAL;
> >>> +           dev_err(dev, "single input LVDS port1 is not supported\n");
> >>
> >>              Are you supporting single input LVDS port0??
> >>
> >>> +   } else if (!port0) {
> >>> +           ret = -EINVAL;
> >>> +           dev_err(dev, "no input LVDS port\n");
> >>> +   }
> >>> +
> >>> +   of_node_put(port0);
> >>> +   of_node_put(port1);
> >>> +
> >>> +   return ret;
> >>> +}
> >>> +
> >>> +static inline void it6263_reset(struct it6263 *it) {
> >>> +   if (!it->reset_gpio)
> >>> +           return;
> >>> +
> >>> +   gpiod_set_value_cansleep(it->reset_gpio, 0);
> >>> +   fsleep(1000);
> >>> +   gpiod_set_value_cansleep(it->reset_gpio, 1);
> >>> +   /* The chip maker says the low pulse should be at least 40ms. */
> >>> +   fsleep(40000);
> >>> +   gpiod_set_value_cansleep(it->reset_gpio, 0);
> >>> +   /* addtional time to wait the high voltage to be stable */
> >>> +   fsleep(5000);
> >>
> >> What about other resets ??
> >>
> >> /* AFE PLL reset and  pclk reset */
> >>
> >>> +}
> >>> +
> >>> +static inline int it6263_lvds_set_i2c_addr(struct it6263 *it) {
> >>> +   int ret;
> >>> +
> >>> +   ret = regmap_write(it->hdmi_regmap, HDMI_REG_LVDS_PORT,
> >>> +                      LVDS_INPUT_CTRL_I2C_ADDR << 1);
> >>> +   if (ret)
> >>> +           return ret;
> >>> +
> >>> +   return regmap_write(it->hdmi_regmap, HDMI_REG_LVDS_PORT_EN, BIT(0));
> >>> +}
> >>> +
> >>> +static inline void it6263_lvds_reset(struct it6263 *it) {
> >>> +   /* AFE PLL reset */
> >>> +   regmap_write_bits(it->lvds_regmap, LVDS_REG_3C, BIT(0), 0x0);
> >>> +   fsleep(1000);
> >>> +   regmap_write_bits(it->lvds_regmap, LVDS_REG_3C, BIT(0), BIT(0));
> >>> +
> >>> +   /* software pixel clock domain reset */
> >>> +   regmap_write_bits(it->lvds_regmap, LVDS_REG_05, REG_SOFT_P_RST,
> >>> +                     REG_SOFT_P_RST);
> >>> +   fsleep(1000);
> >>> +   regmap_write_bits(it->lvds_regmap, LVDS_REG_05, REG_SOFT_P_RST, 0x0);
> >>> +   fsleep(10000);
> >>> +}
> >>> +
> >>> +static inline void it6263_lvds_set_interface(struct it6263 *it) {
> >>> +   /* color depth */
> >>> +   regmap_write_bits(it->lvds_regmap, LVDS_REG_2C, REG_COL_DEP, BIT8);
> >>> +   /* output mapping */
> >>> +   regmap_write_bits(it->lvds_regmap, LVDS_REG_2C, OUT_MAP, JEIDA);
> >>> +
> >>> +   if (it->lvds_dual_link) {
> >>> +           regmap_write_bits(it->lvds_regmap, LVDS_REG_2C, DMODE, DISO);
> >>> +           regmap_write_bits(it->lvds_regmap, LVDS_REG_52, BIT(1), BIT(1));
> >>> +   } else {
> >>> +           regmap_write_bits(it->lvds_regmap, LVDS_REG_2C, DMODE, SISO);
> >>> +           regmap_write_bits(it->lvds_regmap, LVDS_REG_52, BIT(1), 0);
> >>> +   }
> >>> +}
> >>> +
> >>> +static inline void it6263_lvds_set_afe(struct it6263 *it) {
> >>> +   regmap_write(it->lvds_regmap, LVDS_REG_3C, 0xaa);
> >>> +   regmap_write(it->lvds_regmap, LVDS_REG_3F, 0x02);
> >>> +   regmap_write(it->lvds_regmap, LVDS_REG_47, 0xaa);
> >>> +   regmap_write(it->lvds_regmap, LVDS_REG_48, 0x02);
> >>> +   regmap_write(it->lvds_regmap, LVDS_REG_4F, 0x11);
> >>> +
> >>> +   regmap_write_bits(it->lvds_regmap, LVDS_REG_0B, REG_SSC_PCLK_RF,
> >>> +                     REG_SSC_PCLK_RF);
> >>> +   regmap_write_bits(it->lvds_regmap, LVDS_REG_3C, 0x07, 0);
> >>> +   regmap_write_bits(it->lvds_regmap, LVDS_REG_2C, REG_DESSC_ENB,
> >>> +                     REG_DESSC_ENB);
> >>> +}
> >>> +
> >>> +static inline void it6263_lvds_sys_cfg(struct it6263 *it) {
> >>> +   regmap_write_bits(it->lvds_regmap, LVDS_REG_0B, REG_LVDS_IN_SWAP,
> >>> +                     it->lvds_link12_swap ? REG_LVDS_IN_SWAP : 0); }
> >>> +
> >>> +static inline void it6263_lvds_config(struct it6263 *it) {
> >>> +   it6263_lvds_reset(it);
> >>> +   it6263_lvds_set_interface(it);
> >>> +   it6263_lvds_set_afe(it);
> >>> +   it6263_lvds_sys_cfg(it);
> >>> +}
> >>> +
> >>> +static inline void it6263_hdmi_config(struct it6263 *it) {
> >>> +   regmap_write(it->hdmi_regmap, HDMI_REG_SW_RST, HDMI_RST_ALL);
> >>> +   regmap_write(it->hdmi_regmap, HDMI_REG_INPUT_MODE, IN_RGB);
> >>> +   regmap_write_bits(it->hdmi_regmap, HDMI_REG_GCP, HDMI_COLOR_DEPTH,
> >>> +                     HDMI_COLOR_DEPTH_24);
> >>> +   regmap_write_bits(it->hdmi_regmap, HDMI_REG_AVI_DB1,
> >>> +                     AVI_DB1_COLOR_SPACE, AVI_COLOR_SPACE_RGB); }
> >>> +
> >>> +static enum drm_connector_status it6263_detect(struct it6263 *it) {
> >>> +   unsigned int val;
> >>> +
> >>> +   regmap_read(it->hdmi_regmap, HDMI_REG_SYS_STATUS, &val);
> >>> +   if (val & HPDETECT)
> >>> +           return connector_status_connected;
> >>> +   else
> >>> +           return connector_status_disconnected; }
> >>> +
> >>> +static enum drm_connector_status
> >>> +it6263_connector_detect(struct drm_connector *connector, bool force) {
> >>> +   struct it6263 *it = connector_to_it6263(connector);
> >>> +
> >>> +   return it6263_detect(it);
> >>> +}
> >>> +
> >>> +static const struct drm_connector_funcs it6263_connector_funcs = {
> >>> +   .detect = it6263_connector_detect,
> >>> +   .fill_modes = drm_helper_probe_single_connector_modes,
> >>> +   .destroy = drm_connector_cleanup,
> >>> +   .reset = drm_atomic_helper_connector_reset,
> >>> +   .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> >>> +   .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> >>> +};
> >>> +
> >>> +static int it6263_read_edid(void *data, u8 *buf, unsigned int block,
> >>> +size_t len) {
> >>> +   struct it6263 *it = data;
> >>> +   struct regmap *regmap = it->hdmi_regmap;
> >>> +   unsigned int start = (block % 2) * EDID_LENGTH;
> >>> +   unsigned int segment = block >> 1;
> >>> +   unsigned int count, val;
> >>> +   int ret;
> >>> +
> >>> +   regmap_write(regmap, HDMI_REG_DDC_MASTER_CTRL, MASTER_SEL_HOST);
> >>> +   regmap_write(regmap, HDMI_REG_DDC_HEADER, DDC_ADDR << 1);
> >>> +   regmap_write(regmap, HDMI_REG_DDC_EDIDSEG, segment);
> >>> +
> >>> +   while (len) {
> >>> +           /* clear DDC FIFO */
> >>> +           regmap_write(regmap, HDMI_REG_DDC_CMD, DDC_CMD_FIFO_CLR);
> >>> +
> >>> +           ret = regmap_read_poll_timeout(regmap, HDMI_REG_DDC_STATUS,
> >>> +                                          val, val & DDC_DONE,
> >>> +                                          2000, 10000);
> >>> +           if (ret) {
> >>> +                   dev_err(it->dev, "failed to clear DDC FIFO:%d\n", ret);
> >>> +                   return ret;
> >>> +           }
> >>> +
> >>> +           count = len > HDMI_DDC_FIFO_BYTES ? HDMI_DDC_FIFO_BYTES : len;
> >>> +
> >>> +           /* fire the read command */
> >>> +           regmap_write(regmap, HDMI_REG_DDC_REQOFF, start);
> >>> +           regmap_write(regmap, HDMI_REG_DDC_REQCOUNT, count);
> >>> +           regmap_write(regmap, HDMI_REG_DDC_CMD, DDC_CMD_EDID_READ);
> >>> +
> >>> +           start += count;
> >>> +           len -= count;
> >>> +
> >>> +           ret = regmap_read_poll_timeout(regmap, HDMI_REG_DDC_STATUS, val,
> >>> +                                          val & (DDC_DONE | DDC_ERROR),
> >>> +                                          20000, 250000);
> >>> +           if (ret && !(val & DDC_ERROR)) {
> >>> +                   dev_err(it->dev, "failed to read EDID:%d\n", ret);
> >>> +                   return ret;
> >>> +           }
> >>> +
> >>> +           if (val & DDC_ERROR) {
> >>> +                   dev_err(it->dev, "DDC error\n");
> >>> +                   return -EIO;
> >>> +           }
> >>> +
> >>> +           /* cache to buffer */
> >>> +           for (; count > 0; count--) {
> >>> +                   regmap_read(regmap, HDMI_REG_DDC_READFIFO, &val);
> >>> +                   *(buf++) = val;
> >>> +           }
> >>> +   }
> >>> +
> >>> +   return 0;
> >>> +}
> >>> +
> >>> +static int it6263_connector_get_modes(struct drm_connector
> >>> +*connector) {
> >>> +   struct it6263 *it = connector_to_it6263(connector);
> >>> +   const struct drm_edid *drm_edid;
> >>> +   int count;
> >>> +
> >>> +   drm_edid = drm_edid_read_custom(connector, it6263_read_edid, it);
> >>> +
> >>> +   drm_edid_connector_update(connector, drm_edid);
> >>> +   count = drm_edid_connector_add_modes(connector);
> >>> +
> >>> +   drm_edid_free(drm_edid);
> >>> +
> >>> +   return count;
> >>> +}
> >>> +
> >>> +static const struct drm_connector_helper_funcs it6263_connector_helper_funcs = {
> >>> +   .get_modes = it6263_connector_get_modes, };
> >>> +
> >>> +static int it6263_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 *mode = &crtc_state->adjusted_mode;
> >>> +
> >>> +   return mode->clock > MAX_PIXEL_CLOCK_KHZ ? -EINVAL : 0; }
> >>> +
> >>> +static void
> >>> +it6263_bridge_atomic_disable(struct drm_bridge *bridge,
> >>> +                        struct drm_bridge_state *old_bridge_state) {
> >>> +   struct it6263 *it = bridge_to_it6263(bridge);
> >>> +
> >>> +   regmap_write_bits(it->hdmi_regmap, HDMI_REG_GCP, AVMUTE, AVMUTE);
> >>> +   regmap_write(it->hdmi_regmap, HDMI_REG_PKT_GENERAL_CTRL, 0);
> >>> +   regmap_write(it->hdmi_regmap, HDMI_REG_AFE_DRV_CTRL,
> >>> +                AFE_DRV_RST | AFE_DRV_PWD);
> >>> +}
> >>> +
> >>> +static void
> >>> +it6263_bridge_atomic_enable(struct drm_bridge *bridge,
> >>> +                       struct drm_bridge_state *old_bridge_state) {
> >>> +   struct drm_atomic_state *state = old_bridge_state->base.state;
> >>> +   struct it6263 *it = bridge_to_it6263(bridge);
> >>> +   const struct drm_crtc_state *crtc_state;
> >>> +   struct regmap *regmap = it->hdmi_regmap;
> >>> +   const struct drm_display_mode *mode;
> >>> +   struct drm_connector *connector;
> >>> +   bool is_stable = false;
> >>> +   struct drm_crtc *crtc;
> >>> +   unsigned int val;
> >>> +   bool pclk_high;
> >>> +   int i, ret;
> >>> +
> >>> +   connector = drm_atomic_get_new_connector_for_encoder(state,
> >>> +                                                        bridge->encoder);
> >>> +   crtc = drm_atomic_get_new_connector_state(state, connector)->crtc;
> >>> +   crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
> >>> +   mode = &crtc_state->adjusted_mode;
> >>> +
> >>> +   regmap_write(regmap, HDMI_REG_HDMI_MODE, TX_HDMI_MODE);
> >>> +
> >>> +   /* HDMI AFE setup */
> >>> +   pclk_high = mode->clock > HIGH_PIXEL_CLOCK_KHZ ? true : false;
> >>> +   regmap_write(regmap, HDMI_REG_AFE_DRV_CTRL, AFE_DRV_RST);
> >>> +   if (pclk_high)
> >>> +           regmap_write(regmap, HDMI_REG_AFE_XP_CTRL,
> >>> +                        AFE_XP_GAINBIT | AFE_XP_RESETB);
> >>> +   else
> >>> +           regmap_write(regmap, HDMI_REG_AFE_XP_CTRL,
> >>> +                        AFE_XP_ER0 | AFE_XP_RESETB);
> >>> +   regmap_write(regmap, HDMI_REG_AFE_ISW_CTRL, 0x10);
> >>> +   if (pclk_high)
> >>> +           regmap_write(regmap, HDMI_REG_AFE_IP_CTRL,
> >>> +                        AFE_IP_GAINBIT | AFE_IP_RESETB);
> >>> +   else
> >>> +           regmap_write(regmap, HDMI_REG_AFE_IP_CTRL,
> >>> +                        AFE_IP_ER0 | AFE_IP_RESETB);
> >>> +
> >>> +   /* HDMI software video reset */
> >>> +   regmap_write_bits(regmap, HDMI_REG_SW_RST, SOFTV_RST, SOFTV_RST);
> >>> +   fsleep(1000);
> >>> +   regmap_write_bits(regmap, HDMI_REG_SW_RST, SOFTV_RST, 0);
> >>> +
> >>> +   /* reconfigure LVDS and retry several times in case video is instable */
> >>> +   for (i = 0; i < 3; i++) {
> >>> +           ret = regmap_read_poll_timeout(regmap, HDMI_REG_SYS_STATUS, val,
> >>> +                                          val & TXVIDSTABLE,
> >>> +                                          20000, 500000);
> >>> +           if (!ret) {
> >>> +                   is_stable = true;
> >>> +                   break;
> >>> +           }
> >>> +
> >>> +           it6263_lvds_config(it);
> >>> +   }
> >>> +
> >>> +   if (!is_stable)
> >>> +           dev_warn(it->dev, "failed to wait for video stable\n");
> >>> +
> >>> +   /* HDMI AFE reset release and power up */
> >>> +   regmap_write(regmap, HDMI_REG_AFE_DRV_CTRL, 0);
> >>> +
> >>> +   regmap_write_bits(regmap, HDMI_REG_GCP, AVMUTE, 0);
> >>> +
> >>> +   regmap_write(regmap, HDMI_REG_PKT_GENERAL_CTRL, ENABLE_PKT |
> >>> +REPEAT_PKT); }
> >>> +
> >>> +static enum drm_mode_status
> >>> +it6263_bridge_mode_valid(struct drm_bridge *bridge,
> >>> +                    const struct drm_display_info *info,
> >>> +                    const struct drm_display_mode *mode) {
> >>> +   return mode->clock > MAX_PIXEL_CLOCK_KHZ ? MODE_CLOCK_HIGH :
> >>> +MODE_OK; }
> >>> +
> >>> +static int it6263_bridge_attach(struct drm_bridge *bridge,
> >>> +                           enum drm_bridge_attach_flags flags) {
> >>> +   struct it6263 *it = bridge_to_it6263(bridge);
> >>> +   int ret;
> >>> +
> >>> +   ret = drm_bridge_attach(bridge->encoder, it->next_bridge, bridge,
> >>> +                           flags | DRM_BRIDGE_ATTACH_NO_CONNECTOR);
> >>> +   if (ret < 0)
> >>> +           return ret;
> >>> +
> >>> +   if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
> >>> +           return 0;
> >>> +
> >>> +   it->connector.polled = DRM_CONNECTOR_POLL_CONNECT |
> >>> +                          DRM_CONNECTOR_POLL_DISCONNECT;
> >>> +
> >>> +   ret = drm_connector_init(bridge->dev, &it->connector,
> >>> +                            &it6263_connector_funcs,
> >>> +                            DRM_MODE_CONNECTOR_HDMIA);
> >>> +   if (ret)
> >>> +           return ret;
> >>> +
> >>> +   drm_connector_helper_add(&it->connector,
> >>> +                            &it6263_connector_helper_funcs);
> >>> +   drm_connector_attach_encoder(&it->connector, bridge->encoder);
> >>> +
> >>> +   return 0;
> >>> +}
> >>> +
> >>> +static enum drm_connector_status it6263_bridge_detect(struct
> >>> +drm_bridge
> >>> +*bridge) {
> >>> +   struct it6263 *it = bridge_to_it6263(bridge);
> >>> +
> >>> +   return it6263_detect(it);
> >>> +}
> >>> +
> >>> +static const struct drm_edid *
> >>> +it6263_bridge_edid_read(struct drm_bridge *bridge,
> >>> +                   struct drm_connector *connector)
> >>> +{
> >>> +   struct it6263 *it = bridge_to_it6263(bridge);
> >>> +
> >>> +   return drm_edid_read_custom(connector, it6263_read_edid, it); }
> >>> +
> >>> +static u32 *
> >>> +it6263_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
> >>> +                                   struct drm_bridge_state *bridge_state,
> >>> +                                   struct drm_crtc_state *crtc_state,
> >>> +                                   struct drm_connector_state *conn_state,
> >>> +                                   u32 output_fmt,
> >>> +                                   unsigned int *num_input_fmts)
> >>> +{
> >>> +   u32 *input_fmts;
> >>> +
> >>> +   input_fmts = kmalloc(sizeof(*input_fmts), GFP_KERNEL);
> >>> +   if (!input_fmts) {
> >>> +           *num_input_fmts = 0;
> >>> +           return NULL;
> >>> +   }
> >>> +
> >>> +   input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA;
> >>
> >> Why is it hardcoded? What about supporting VESA??
> >>
> >>> +   *num_input_fmts = 1;
> >>> +
> >>> +   return input_fmts;
> >>> +}
> >>> +
> >>> +static const struct drm_bridge_funcs it6263_bridge_funcs = {
> >>> +   .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,
> >>> +   .attach = it6263_bridge_attach,
> >>> +   .mode_valid = it6263_bridge_mode_valid,
> >>> +   .atomic_disable = it6263_bridge_atomic_disable,
> >>> +   .atomic_enable = it6263_bridge_atomic_enable,
> >>> +   .atomic_check = it6263_bridge_atomic_check,
> >>> +   .detect = it6263_bridge_detect,
> >>> +   .edid_read = it6263_bridge_edid_read,
> >>> +   .atomic_get_input_bus_fmts =
> >>> +it6263_bridge_atomic_get_input_bus_fmts,
> >>> +};
> >
> > Like [1]
> > static const struct drm_bridge_funcs it6263_bridge_funcs = {
> >       .attach = it6263_bridge_attach,
> >       .mode_set = it6263_bridge_mode_set,
> >       .disable = it6263_bridge_disable,
> >       .enable = it6263_bridge_enable,
> >       .get_edid = it6263_bridge_get_edid,
> >       .detect = it6263_bridge_detect,
> > };
> >
> > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c?h=v6.12-rc1#n998
> >
> > Is it not sufficient for your use case??
>
> If we decide to document the LVDS data mapping in dt-binding,
> then it is practically ok to use the non-atomic callbacks like
> the adv7511 driver, otherwise, the atomic callbacks are required
> due to the bus format negotiation.

Please use atomic callbacks, it's better even if it means more code.

>
> >
> > Cheers,
> > Biju
> >
> >>> +
> >>> +static int it6263_probe(struct i2c_client *client) {
> >>> +   struct device *dev = &client->dev;
> >>> +   struct it6263 *it;
> >>> +   int ret;
> >>> +
> >>> +   it = devm_kzalloc(dev, sizeof(*it), GFP_KERNEL);
> >>> +   if (!it)
> >>> +           return -ENOMEM;
> >>> +
> >>> +   it->dev = dev;
> >>> +   it->hdmi_i2c = client;
> >>> +
> >>> +   it->hdmi_regmap = devm_regmap_init_i2c(client,
> >>> +                                          &it6263_hdmi_regmap_config);
> >>> +   if (IS_ERR(it->hdmi_regmap))
> >>> +           return dev_err_probe(dev, PTR_ERR(it->hdmi_regmap),
> >>> +                                "failed to init I2C regmap for HDMI\n");
> >>> +
> >>> +   it->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
> >>> +   if (IS_ERR(it->reset_gpio))
> >>> +           return dev_err_probe(dev, PTR_ERR(it->reset_gpio),
> >>> +                                "failed to get reset gpio\n");
> >>> +
> >>> +   ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(it6263_supplies),
> >>> +                                        it6263_supplies);
> >>> +   if (ret)
> >>> +           return dev_err_probe(dev, ret, "failed to get power supplies\n");
> >>> +
> >>> +   ret = it6263_parse_dt(it);
> >>> +   if (ret)
> >>> +           return ret;
> >>> +
> >>> +   it6263_reset(it);
> >>> +
> >>> +   ret = it6263_lvds_set_i2c_addr(it);
> >>> +   if (ret)
> >>> +           return dev_err_probe(dev, ret, "failed to set I2C addr\n");
> >>> +
> >>> +   it->lvds_i2c = devm_i2c_new_dummy_device(dev, client->adapter,
> >>> +                                            LVDS_INPUT_CTRL_I2C_ADDR);
> >>> +   if (IS_ERR(it->lvds_i2c))
> >>> +           dev_err_probe(it->dev, PTR_ERR(it->lvds_i2c),
> >>> +                         "failed to allocate I2C device for LVDS\n");
> >>
> >> Maybe use action_or_reset and call i2c_unregister_device();
> >>
> >>> +
> >>> +   it->lvds_regmap = devm_regmap_init_i2c(it->lvds_i2c,
> >>> +                                          &it6263_lvds_regmap_config);
> >>> +   if (IS_ERR(it->lvds_regmap))
> >>> +           return dev_err_probe(dev, PTR_ERR(it->lvds_regmap),
> >>> +                                "failed to init I2C regmap for LVDS\n");
> >>
> >>> +
> >>> +   it6263_lvds_config(it);
> >>> +   it6263_hdmi_config(it);
> >>
> >>> +
> >>> +   i2c_set_clientdata(client, it);
> >>> +
> >>> +   it->bridge.funcs = &it6263_bridge_funcs;
> >>> +   it->bridge.of_node = dev->of_node;
> >>> +   it->bridge.ops = DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_DETECT;
> >>
> >>      it->bridge.type = DRM_MODE_CONNECTOR_HDMIA; ??
> >>
> >>> +   drm_bridge_add(&it->bridge);
> >>> +
> >>> +   return 0;
> >>> +}
> >>> +
> >>> +static void it6263_remove(struct i2c_client *client) {
> >>> +   struct it6263 *it = i2c_get_clientdata(client);
> >>> +
> >>> +   drm_bridge_remove(&it->bridge);
> >>
> >>> +}
> >>> +
> >>> +static const struct of_device_id it6263_of_match[] = {
> >>> +   { .compatible = "ite,it6263", },
> >>> +   { }
> >>> +};
> >>> +MODULE_DEVICE_TABLE(of, it6263_of_match);
> >>> +
> >>> +static const struct i2c_device_id it6263_i2c_ids[] = {
> >>> +   { "it6263", 0 },
> >>> +   { }
> >>> +};
> >>> +MODULE_DEVICE_TABLE(i2c, it6263_i2c_ids);
> >>> +
> >>> +static struct i2c_driver it6263_driver = {
> >>> +   .probe = it6263_probe,
> >>> +   .remove = it6263_remove,
> >>> +   .driver = {
> >>> +           .name = "it6263",
> >>> +           .of_match_table = it6263_of_match,
> >>> +   },
> >>> +   .id_table = it6263_i2c_ids,
> >>> +};
> >>> +module_i2c_driver(it6263_driver);
> >>> +
> >>> +MODULE_DESCRIPTION("ITE Tech. Inc. IT6263 LVDS/HDMI bridge");
> >>> +MODULE_AUTHOR("Liu Ying <victor.liu@nxp.com>");
> >>> +MODULE_LICENSE("GPL");
> >>> --
> >>> 2.34.1
> >>>
> >
>
> --
> Regards,
> Liu Ying
>


-- 
With best wishes
Dmitry

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

* Re: [PATCH 4/8] drm/bridge: fsl-ldb: Use clk_round_rate() to validate "ldb" clock rate
  2024-09-30  7:55     ` Liu Ying
@ 2024-10-11 11:06       ` Maxime Ripard
  2024-10-12  6:18         ` Liu Ying
  0 siblings, 1 reply; 38+ messages in thread
From: Maxime Ripard @ 2024-10-11 11:06 UTC (permalink / raw)
  To: Liu Ying
  Cc: dri-devel, devicetree, linux-kernel, imx, linux-arm-kernel,
	andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart, jonas,
	jernej.skrabec, maarten.lankhorst, tzimmermann, airlied, simona,
	robh, krzk+dt, conor+dt, shawnguo, s.hauer, kernel, festevam,
	catalin.marinas, will, quic_bjorande, geert+renesas,
	dmitry.baryshkov, arnd, nfraprado, o.rempel, y.moog

[-- Attachment #1: Type: text/plain, Size: 4711 bytes --]

On Mon, Sep 30, 2024 at 03:55:30PM GMT, Liu Ying wrote:
> On 09/30/2024, Maxime Ripard wrote:
> > On Mon, Sep 30, 2024 at 01:28:59PM GMT, Liu Ying wrote:
> >> Multiple display modes could be read from a display device's EDID.
> >> Use clk_round_rate() to validate the "ldb" clock rate for each mode
> >> in drm_bridge_funcs::mode_valid() to filter unsupported modes out.
> >>
> >> Also, if the "ldb" clock and the pixel clock are sibling in clock
> >> tree, use clk_round_rate() to validate the pixel clock rate against
> >> the "ldb" clock.  This is not done in display controller driver
> >> because drm_crtc_helper_funcs::mode_valid() may not decide to do
> >> the validation or not if multiple encoders are connected to the CRTC,
> >> e.g., i.MX93 LCDIF may connect with MIPI DSI controller, LDB and
> >> parallel display output simultaneously.
> >>
> >> Signed-off-by: Liu Ying <victor.liu@nxp.com>
> >> ---
> >>  drivers/gpu/drm/bridge/fsl-ldb.c | 22 ++++++++++++++++++++++
> >>  1 file changed, 22 insertions(+)
> >>
> >> diff --git a/drivers/gpu/drm/bridge/fsl-ldb.c b/drivers/gpu/drm/bridge/fsl-ldb.c
> >> index b559f3e0bef6..ee8471c86617 100644
> >> --- a/drivers/gpu/drm/bridge/fsl-ldb.c
> >> +++ b/drivers/gpu/drm/bridge/fsl-ldb.c
> >> @@ -11,6 +11,7 @@
> >>  #include <linux/of_graph.h>
> >>  #include <linux/platform_device.h>
> >>  #include <linux/regmap.h>
> >> +#include <linux/units.h>
> >>  
> >>  #include <drm/drm_atomic_helper.h>
> >>  #include <drm/drm_bridge.h>
> >> @@ -64,6 +65,7 @@ struct fsl_ldb_devdata {
> >>  	u32 lvds_ctrl;
> >>  	bool lvds_en_bit;
> >>  	bool single_ctrl_reg;
> >> +	bool ldb_clk_pixel_clk_sibling;
> >>  };
> >>  
> >>  static const struct fsl_ldb_devdata fsl_ldb_devdata[] = {
> >> @@ -74,11 +76,13 @@ static const struct fsl_ldb_devdata fsl_ldb_devdata[] = {
> >>  	[IMX8MP_LDB] = {
> >>  		.ldb_ctrl = 0x5c,
> >>  		.lvds_ctrl = 0x128,
> >> +		.ldb_clk_pixel_clk_sibling = true,
> >>  	},
> >>  	[IMX93_LDB] = {
> >>  		.ldb_ctrl = 0x20,
> >>  		.lvds_ctrl = 0x24,
> >>  		.lvds_en_bit = true,
> >> +		.ldb_clk_pixel_clk_sibling = true,
> >>  	},
> >>  };
> >>  
> >> @@ -269,11 +273,29 @@ fsl_ldb_mode_valid(struct drm_bridge *bridge,
> >>  		   const struct drm_display_info *info,
> >>  		   const struct drm_display_mode *mode)
> >>  {
> >> +	unsigned long link_freq, pclk_rate, rounded_pclk_rate;
> >>  	struct fsl_ldb *fsl_ldb = to_fsl_ldb(bridge);
> >>  
> >>  	if (mode->clock > (fsl_ldb_is_dual(fsl_ldb) ? 160000 : 80000))
> >>  		return MODE_CLOCK_HIGH;
> >>  
> >> +	/* Validate "ldb" clock rate. */
> >> +	link_freq = fsl_ldb_link_frequency(fsl_ldb, mode->clock);
> >> +	if (link_freq != clk_round_rate(fsl_ldb->clk, link_freq))
> >> +		return MODE_NOCLOCK;
> >> +
> >> +	/*
> >> +	 * Use "ldb" clock to validate pixel clock rate,
> >> +	 * if the two clocks are sibling.
> >> +	 */
> >> +	if (fsl_ldb->devdata->ldb_clk_pixel_clk_sibling) {
> >> +		pclk_rate = mode->clock * HZ_PER_KHZ;
> >> +
> >> +		rounded_pclk_rate = clk_round_rate(fsl_ldb->clk, pclk_rate);
> >> +		if (rounded_pclk_rate != pclk_rate)
> >> +			return MODE_NOCLOCK;
> >> +	}
> >> +
> > 
> > I guess this is to workaround the fact that the parent rate would be
> > changed, and thus the sibling rate as well? This should be documented in
> > a comment if so.
> 
> This is to workaround the fact that the display controller driver
> (lcdif_kms.c) cannot do the mode validation against pixel clock, as
> the commit message mentions.

That part is still not super clear to me, but it's also not super
important to the discussion.

My point is: from a clock API standpoint, there's absolutely no reason
to consider sibling clocks. clk_round_rate() should give you the rate
you want. If it affects other clocks it shouldn't, it's a clock driver
bug.

You might want to workaround it, but this is definitely not something
you should gloss over: it's a hack, it needs to be documented as such.

> The parent clock is IMX8MP_VIDEO_PLL1_OUT and it's clock rate is not
> supposed to be changed any more once IMX8MP_VIDEO_PLL1 clock rate is
> set by using DT assigned-clock-rates property.  For i.MX8MP EVK, the
> clock rate is assigned to 1039500000Hz in imx8mp.dtsi in media_blk_ctrl
> node.

There's two things wrong with what you just described:

  - assigned-clock-rates never provided the guarantee that the clock
    rate wouldn't change later on. So if you rely on that, here's your
    first bug.

  - If the parent clock rate must not change, why does that clock has
    SET_RATE_PARENT then? Because that's the bug you're trying to work
    around.

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 273 bytes --]

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

* Re: [PATCH 4/8] drm/bridge: fsl-ldb: Use clk_round_rate() to validate "ldb" clock rate
  2024-10-11 11:06       ` Maxime Ripard
@ 2024-10-12  6:18         ` Liu Ying
  2024-10-14  9:22           ` Maxime Ripard
  0 siblings, 1 reply; 38+ messages in thread
From: Liu Ying @ 2024-10-12  6:18 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: dri-devel, devicetree, linux-kernel, imx, linux-arm-kernel,
	andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart, jonas,
	jernej.skrabec, maarten.lankhorst, tzimmermann, airlied, simona,
	robh, krzk+dt, conor+dt, shawnguo, s.hauer, kernel, festevam,
	catalin.marinas, will, quic_bjorande, geert+renesas,
	dmitry.baryshkov, arnd, nfraprado, o.rempel, y.moog

On 10/11/2024, Maxime Ripard wrote:
> On Mon, Sep 30, 2024 at 03:55:30PM GMT, Liu Ying wrote:
>> On 09/30/2024, Maxime Ripard wrote:
>>> On Mon, Sep 30, 2024 at 01:28:59PM GMT, Liu Ying wrote:
>>>> Multiple display modes could be read from a display device's EDID.
>>>> Use clk_round_rate() to validate the "ldb" clock rate for each mode
>>>> in drm_bridge_funcs::mode_valid() to filter unsupported modes out.
>>>>
>>>> Also, if the "ldb" clock and the pixel clock are sibling in clock
>>>> tree, use clk_round_rate() to validate the pixel clock rate against
>>>> the "ldb" clock.  This is not done in display controller driver
>>>> because drm_crtc_helper_funcs::mode_valid() may not decide to do
>>>> the validation or not if multiple encoders are connected to the CRTC,
>>>> e.g., i.MX93 LCDIF may connect with MIPI DSI controller, LDB and
>>>> parallel display output simultaneously.
>>>>
>>>> Signed-off-by: Liu Ying <victor.liu@nxp.com>
>>>> ---
>>>>  drivers/gpu/drm/bridge/fsl-ldb.c | 22 ++++++++++++++++++++++
>>>>  1 file changed, 22 insertions(+)
>>>>
>>>> diff --git a/drivers/gpu/drm/bridge/fsl-ldb.c b/drivers/gpu/drm/bridge/fsl-ldb.c
>>>> index b559f3e0bef6..ee8471c86617 100644
>>>> --- a/drivers/gpu/drm/bridge/fsl-ldb.c
>>>> +++ b/drivers/gpu/drm/bridge/fsl-ldb.c
>>>> @@ -11,6 +11,7 @@
>>>>  #include <linux/of_graph.h>
>>>>  #include <linux/platform_device.h>
>>>>  #include <linux/regmap.h>
>>>> +#include <linux/units.h>
>>>>  
>>>>  #include <drm/drm_atomic_helper.h>
>>>>  #include <drm/drm_bridge.h>
>>>> @@ -64,6 +65,7 @@ struct fsl_ldb_devdata {
>>>>  	u32 lvds_ctrl;
>>>>  	bool lvds_en_bit;
>>>>  	bool single_ctrl_reg;
>>>> +	bool ldb_clk_pixel_clk_sibling;
>>>>  };
>>>>  
>>>>  static const struct fsl_ldb_devdata fsl_ldb_devdata[] = {
>>>> @@ -74,11 +76,13 @@ static const struct fsl_ldb_devdata fsl_ldb_devdata[] = {
>>>>  	[IMX8MP_LDB] = {
>>>>  		.ldb_ctrl = 0x5c,
>>>>  		.lvds_ctrl = 0x128,
>>>> +		.ldb_clk_pixel_clk_sibling = true,
>>>>  	},
>>>>  	[IMX93_LDB] = {
>>>>  		.ldb_ctrl = 0x20,
>>>>  		.lvds_ctrl = 0x24,
>>>>  		.lvds_en_bit = true,
>>>> +		.ldb_clk_pixel_clk_sibling = true,
>>>>  	},
>>>>  };
>>>>  
>>>> @@ -269,11 +273,29 @@ fsl_ldb_mode_valid(struct drm_bridge *bridge,
>>>>  		   const struct drm_display_info *info,
>>>>  		   const struct drm_display_mode *mode)
>>>>  {
>>>> +	unsigned long link_freq, pclk_rate, rounded_pclk_rate;
>>>>  	struct fsl_ldb *fsl_ldb = to_fsl_ldb(bridge);
>>>>  
>>>>  	if (mode->clock > (fsl_ldb_is_dual(fsl_ldb) ? 160000 : 80000))
>>>>  		return MODE_CLOCK_HIGH;
>>>>  
>>>> +	/* Validate "ldb" clock rate. */
>>>> +	link_freq = fsl_ldb_link_frequency(fsl_ldb, mode->clock);
>>>> +	if (link_freq != clk_round_rate(fsl_ldb->clk, link_freq))
>>>> +		return MODE_NOCLOCK;
>>>> +
>>>> +	/*
>>>> +	 * Use "ldb" clock to validate pixel clock rate,
>>>> +	 * if the two clocks are sibling.
>>>> +	 */
>>>> +	if (fsl_ldb->devdata->ldb_clk_pixel_clk_sibling) {
>>>> +		pclk_rate = mode->clock * HZ_PER_KHZ;
>>>> +
>>>> +		rounded_pclk_rate = clk_round_rate(fsl_ldb->clk, pclk_rate);
>>>> +		if (rounded_pclk_rate != pclk_rate)
>>>> +			return MODE_NOCLOCK;
>>>> +	}
>>>> +
>>>
>>> I guess this is to workaround the fact that the parent rate would be
>>> changed, and thus the sibling rate as well? This should be documented in
>>> a comment if so.
>>
>> This is to workaround the fact that the display controller driver
>> (lcdif_kms.c) cannot do the mode validation against pixel clock, as
>> the commit message mentions.
> 
> That part is still not super clear to me, but it's also not super
> important to the discussion.

As kerneldoc of drm_crtc_helper_funcs::mode_valid mentions that
it is not allowed to look at anything else but the passed-in mode,
it doesn't know of the connected encoder(s)/bridge(s) and thus
cannot decide if it should do mode validation against pixel clock
or not.  Encoder/bridge drivers could adjust pixel clock rates
for display modes.  So, mode validation against pixel clock should
be done in this bridge driver.

In fact, the pixel clock should have been defined as a DT property
in fsl,ldb.yaml because the clock routes to LDB as an input signal.
However, it's too late...  If the DT property was defined in the
first place, then this driver can naturally do mode validation
against pixel clock instead of this workaround.

> 
> My point is: from a clock API standpoint, there's absolutely no reason
> to consider sibling clocks. clk_round_rate() should give you the rate

Agree, but it's a workaround.

> you want. If it affects other clocks it shouldn't, it's a clock driver
> bug.

The sibling clocks are the same type of clocks from HW design
point of view and derived from the same clock parent/PLL.
That's the reason why the workaround works.

> 
> You might want to workaround it, but this is definitely not something
> you should gloss over: it's a hack, it needs to be documented as such.

I can add some documentation in next version to clarify this
a bit.

> 
>> The parent clock is IMX8MP_VIDEO_PLL1_OUT and it's clock rate is not
>> supposed to be changed any more once IMX8MP_VIDEO_PLL1 clock rate is
>> set by using DT assigned-clock-rates property.  For i.MX8MP EVK, the
>> clock rate is assigned to 1039500000Hz in imx8mp.dtsi in media_blk_ctrl
>> node.
> 
> There's two things wrong with what you just described:
> 
>   - assigned-clock-rates never provided the guarantee that the clock
>     rate wouldn't change later on. So if you rely on that, here's your
>     first bug.

I'm not relying on that.  Instead, the PLL clock rate is not
supposed to change since IMX8MP_CLK_MEDIA_LDB clock("ldb" clock
parent clock) hasn't the CLK_SET_RATE_PARENT flag.  And, we don't
want to change the PLL clock rate at runtime because the PLL can
be used by i.MX8MP MIPI DSI and LDB display pipelines at the same
time, driven by two LCDIFv3 display controllers respectively with
two imx-lcdif KMS instances.  We don't want to see the two display
pipelines to step on each other.

> 
>   - If the parent clock rate must not change, why does that clock has
>     SET_RATE_PARENT then? Because that's the bug you're trying to work
>     around.

IMX8MP_CLK_MEDIA_LDB clock hasn't the CLK_SET_RATE_PARENT flag.
I'm fine with the "ldb" clock tree from the current clock driver
PoV - just trying to validate pixel clock rate as a workaround.

> 
> Maxime

-- 
Regards,
Liu Ying


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

* Re: [PATCH 4/8] drm/bridge: fsl-ldb: Use clk_round_rate() to validate "ldb" clock rate
  2024-10-12  6:18         ` Liu Ying
@ 2024-10-14  9:22           ` Maxime Ripard
  2024-10-14  9:40             ` Liu Ying
  0 siblings, 1 reply; 38+ messages in thread
From: Maxime Ripard @ 2024-10-14  9:22 UTC (permalink / raw)
  To: Liu Ying
  Cc: dri-devel, devicetree, linux-kernel, imx, linux-arm-kernel,
	andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart, jonas,
	jernej.skrabec, maarten.lankhorst, tzimmermann, airlied, simona,
	robh, krzk+dt, conor+dt, shawnguo, s.hauer, kernel, festevam,
	catalin.marinas, will, quic_bjorande, geert+renesas,
	dmitry.baryshkov, arnd, nfraprado, o.rempel, y.moog

[-- Attachment #1: Type: text/plain, Size: 7342 bytes --]

On Sat, Oct 12, 2024 at 02:18:16PM GMT, Liu Ying wrote:
> On 10/11/2024, Maxime Ripard wrote:
> > On Mon, Sep 30, 2024 at 03:55:30PM GMT, Liu Ying wrote:
> >> On 09/30/2024, Maxime Ripard wrote:
> >>> On Mon, Sep 30, 2024 at 01:28:59PM GMT, Liu Ying wrote:
> >>>> Multiple display modes could be read from a display device's EDID.
> >>>> Use clk_round_rate() to validate the "ldb" clock rate for each mode
> >>>> in drm_bridge_funcs::mode_valid() to filter unsupported modes out.
> >>>>
> >>>> Also, if the "ldb" clock and the pixel clock are sibling in clock
> >>>> tree, use clk_round_rate() to validate the pixel clock rate against
> >>>> the "ldb" clock.  This is not done in display controller driver
> >>>> because drm_crtc_helper_funcs::mode_valid() may not decide to do
> >>>> the validation or not if multiple encoders are connected to the CRTC,
> >>>> e.g., i.MX93 LCDIF may connect with MIPI DSI controller, LDB and
> >>>> parallel display output simultaneously.
> >>>>
> >>>> Signed-off-by: Liu Ying <victor.liu@nxp.com>
> >>>> ---
> >>>>  drivers/gpu/drm/bridge/fsl-ldb.c | 22 ++++++++++++++++++++++
> >>>>  1 file changed, 22 insertions(+)
> >>>>
> >>>> diff --git a/drivers/gpu/drm/bridge/fsl-ldb.c b/drivers/gpu/drm/bridge/fsl-ldb.c
> >>>> index b559f3e0bef6..ee8471c86617 100644
> >>>> --- a/drivers/gpu/drm/bridge/fsl-ldb.c
> >>>> +++ b/drivers/gpu/drm/bridge/fsl-ldb.c
> >>>> @@ -11,6 +11,7 @@
> >>>>  #include <linux/of_graph.h>
> >>>>  #include <linux/platform_device.h>
> >>>>  #include <linux/regmap.h>
> >>>> +#include <linux/units.h>
> >>>>  
> >>>>  #include <drm/drm_atomic_helper.h>
> >>>>  #include <drm/drm_bridge.h>
> >>>> @@ -64,6 +65,7 @@ struct fsl_ldb_devdata {
> >>>>  	u32 lvds_ctrl;
> >>>>  	bool lvds_en_bit;
> >>>>  	bool single_ctrl_reg;
> >>>> +	bool ldb_clk_pixel_clk_sibling;
> >>>>  };
> >>>>  
> >>>>  static const struct fsl_ldb_devdata fsl_ldb_devdata[] = {
> >>>> @@ -74,11 +76,13 @@ static const struct fsl_ldb_devdata fsl_ldb_devdata[] = {
> >>>>  	[IMX8MP_LDB] = {
> >>>>  		.ldb_ctrl = 0x5c,
> >>>>  		.lvds_ctrl = 0x128,
> >>>> +		.ldb_clk_pixel_clk_sibling = true,
> >>>>  	},
> >>>>  	[IMX93_LDB] = {
> >>>>  		.ldb_ctrl = 0x20,
> >>>>  		.lvds_ctrl = 0x24,
> >>>>  		.lvds_en_bit = true,
> >>>> +		.ldb_clk_pixel_clk_sibling = true,
> >>>>  	},
> >>>>  };
> >>>>  
> >>>> @@ -269,11 +273,29 @@ fsl_ldb_mode_valid(struct drm_bridge *bridge,
> >>>>  		   const struct drm_display_info *info,
> >>>>  		   const struct drm_display_mode *mode)
> >>>>  {
> >>>> +	unsigned long link_freq, pclk_rate, rounded_pclk_rate;
> >>>>  	struct fsl_ldb *fsl_ldb = to_fsl_ldb(bridge);
> >>>>  
> >>>>  	if (mode->clock > (fsl_ldb_is_dual(fsl_ldb) ? 160000 : 80000))
> >>>>  		return MODE_CLOCK_HIGH;
> >>>>  
> >>>> +	/* Validate "ldb" clock rate. */
> >>>> +	link_freq = fsl_ldb_link_frequency(fsl_ldb, mode->clock);
> >>>> +	if (link_freq != clk_round_rate(fsl_ldb->clk, link_freq))
> >>>> +		return MODE_NOCLOCK;
> >>>> +
> >>>> +	/*
> >>>> +	 * Use "ldb" clock to validate pixel clock rate,
> >>>> +	 * if the two clocks are sibling.
> >>>> +	 */
> >>>> +	if (fsl_ldb->devdata->ldb_clk_pixel_clk_sibling) {
> >>>> +		pclk_rate = mode->clock * HZ_PER_KHZ;
> >>>> +
> >>>> +		rounded_pclk_rate = clk_round_rate(fsl_ldb->clk, pclk_rate);
> >>>> +		if (rounded_pclk_rate != pclk_rate)
> >>>> +			return MODE_NOCLOCK;
> >>>> +	}
> >>>> +
> >>>
> >>> I guess this is to workaround the fact that the parent rate would be
> >>> changed, and thus the sibling rate as well? This should be documented in
> >>> a comment if so.
> >>
> >> This is to workaround the fact that the display controller driver
> >> (lcdif_kms.c) cannot do the mode validation against pixel clock, as
> >> the commit message mentions.
> > 
> > That part is still not super clear to me, but it's also not super
> > important to the discussion.
> 
> As kerneldoc of drm_crtc_helper_funcs::mode_valid mentions that
> it is not allowed to look at anything else but the passed-in mode,
> it doesn't know of the connected encoder(s)/bridge(s) and thus
> cannot decide if it should do mode validation against pixel clock
> or not.  Encoder/bridge drivers could adjust pixel clock rates
> for display modes.  So, mode validation against pixel clock should
> be done in this bridge driver.
> 
> In fact, the pixel clock should have been defined as a DT property
> in fsl,ldb.yaml because the clock routes to LDB as an input signal.
> However, it's too late...  If the DT property was defined in the
> first place, then this driver can naturally do mode validation
> against pixel clock instead of this workaround.
> 
> > 
> > My point is: from a clock API standpoint, there's absolutely no reason
> > to consider sibling clocks. clk_round_rate() should give you the rate
> 
> Agree, but it's a workaround.
> 
> > you want. If it affects other clocks it shouldn't, it's a clock driver
> > bug.
> 
> The sibling clocks are the same type of clocks from HW design
> point of view and derived from the same clock parent/PLL.
> That's the reason why the workaround works.
> 
> > 
> > You might want to workaround it, but this is definitely not something
> > you should gloss over: it's a hack, it needs to be documented as such.
> 
> I can add some documentation in next version to clarify this
> a bit.
> 
> > 
> >> The parent clock is IMX8MP_VIDEO_PLL1_OUT and it's clock rate is not
> >> supposed to be changed any more once IMX8MP_VIDEO_PLL1 clock rate is
> >> set by using DT assigned-clock-rates property.  For i.MX8MP EVK, the
> >> clock rate is assigned to 1039500000Hz in imx8mp.dtsi in media_blk_ctrl
> >> node.
> > 
> > There's two things wrong with what you just described:
> > 
> >   - assigned-clock-rates never provided the guarantee that the clock
> >     rate wouldn't change later on. So if you rely on that, here's your
> >     first bug.
> 
> I'm not relying on that.

Sure you do. If anything in the kernel changes the rate of the
VIDEO_PLL1 clock, then it's game over and "clock rate is not supposed to
be changed any more once IMX8MP_VIDEO_PLL1 clock rate is set by using DT
assigned-clock-rates property." isn't true anymore.

> Instead, the PLL clock rate is not supposed to change since
> IMX8MP_CLK_MEDIA_LDB clock("ldb" clock parent clock) hasn't the
> CLK_SET_RATE_PARENT flag. And, we don't want to change the PLL clock
> rate at runtime because the PLL can be used by i.MX8MP MIPI DSI and
> LDB display pipelines at the same time, driven by two LCDIFv3 display
> controllers respectively with two imx-lcdif KMS instances. We don't
> want to see the two display pipelines to step on each other.
> 
> > 
> >   - If the parent clock rate must not change, why does that clock has
> >     SET_RATE_PARENT then? Because that's the bug you're trying to work
> >     around.
> 
> IMX8MP_CLK_MEDIA_LDB clock hasn't the CLK_SET_RATE_PARENT flag.
> I'm fine with the "ldb" clock tree from the current clock driver
> PoV - just trying to validate pixel clock rate as a workaround.

As far as I can see, the ldb clock is IMX8MP_CLK_MEDIA_LDB_ROOT in
imx8mp.dtsi. That clock is defined using imx_clk_hw_gate2_shared2 that
does set CLK_SET_RATE_PARENT.

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 273 bytes --]

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

* Re: [PATCH 4/8] drm/bridge: fsl-ldb: Use clk_round_rate() to validate "ldb" clock rate
  2024-10-14  9:22           ` Maxime Ripard
@ 2024-10-14  9:40             ` Liu Ying
  0 siblings, 0 replies; 38+ messages in thread
From: Liu Ying @ 2024-10-14  9:40 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: dri-devel, devicetree, linux-kernel, imx, linux-arm-kernel,
	andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart, jonas,
	jernej.skrabec, maarten.lankhorst, tzimmermann, airlied, simona,
	robh, krzk+dt, conor+dt, shawnguo, s.hauer, kernel, festevam,
	catalin.marinas, will, quic_bjorande, geert+renesas,
	dmitry.baryshkov, arnd, nfraprado, o.rempel, y.moog

On 10/14/2024, Maxime Ripard wrote:
> On Sat, Oct 12, 2024 at 02:18:16PM GMT, Liu Ying wrote:
>> On 10/11/2024, Maxime Ripard wrote:
>>> On Mon, Sep 30, 2024 at 03:55:30PM GMT, Liu Ying wrote:
>>>> On 09/30/2024, Maxime Ripard wrote:
>>>>> On Mon, Sep 30, 2024 at 01:28:59PM GMT, Liu Ying wrote:
>>>>>> Multiple display modes could be read from a display device's EDID.
>>>>>> Use clk_round_rate() to validate the "ldb" clock rate for each mode
>>>>>> in drm_bridge_funcs::mode_valid() to filter unsupported modes out.
>>>>>>
>>>>>> Also, if the "ldb" clock and the pixel clock are sibling in clock
>>>>>> tree, use clk_round_rate() to validate the pixel clock rate against
>>>>>> the "ldb" clock.  This is not done in display controller driver
>>>>>> because drm_crtc_helper_funcs::mode_valid() may not decide to do
>>>>>> the validation or not if multiple encoders are connected to the CRTC,
>>>>>> e.g., i.MX93 LCDIF may connect with MIPI DSI controller, LDB and
>>>>>> parallel display output simultaneously.
>>>>>>
>>>>>> Signed-off-by: Liu Ying <victor.liu@nxp.com>
>>>>>> ---
>>>>>>  drivers/gpu/drm/bridge/fsl-ldb.c | 22 ++++++++++++++++++++++
>>>>>>  1 file changed, 22 insertions(+)
>>>>>>
>>>>>> diff --git a/drivers/gpu/drm/bridge/fsl-ldb.c b/drivers/gpu/drm/bridge/fsl-ldb.c
>>>>>> index b559f3e0bef6..ee8471c86617 100644
>>>>>> --- a/drivers/gpu/drm/bridge/fsl-ldb.c
>>>>>> +++ b/drivers/gpu/drm/bridge/fsl-ldb.c
>>>>>> @@ -11,6 +11,7 @@
>>>>>>  #include <linux/of_graph.h>
>>>>>>  #include <linux/platform_device.h>
>>>>>>  #include <linux/regmap.h>
>>>>>> +#include <linux/units.h>
>>>>>>  
>>>>>>  #include <drm/drm_atomic_helper.h>
>>>>>>  #include <drm/drm_bridge.h>
>>>>>> @@ -64,6 +65,7 @@ struct fsl_ldb_devdata {
>>>>>>  	u32 lvds_ctrl;
>>>>>>  	bool lvds_en_bit;
>>>>>>  	bool single_ctrl_reg;
>>>>>> +	bool ldb_clk_pixel_clk_sibling;
>>>>>>  };
>>>>>>  
>>>>>>  static const struct fsl_ldb_devdata fsl_ldb_devdata[] = {
>>>>>> @@ -74,11 +76,13 @@ static const struct fsl_ldb_devdata fsl_ldb_devdata[] = {
>>>>>>  	[IMX8MP_LDB] = {
>>>>>>  		.ldb_ctrl = 0x5c,
>>>>>>  		.lvds_ctrl = 0x128,
>>>>>> +		.ldb_clk_pixel_clk_sibling = true,
>>>>>>  	},
>>>>>>  	[IMX93_LDB] = {
>>>>>>  		.ldb_ctrl = 0x20,
>>>>>>  		.lvds_ctrl = 0x24,
>>>>>>  		.lvds_en_bit = true,
>>>>>> +		.ldb_clk_pixel_clk_sibling = true,
>>>>>>  	},
>>>>>>  };
>>>>>>  
>>>>>> @@ -269,11 +273,29 @@ fsl_ldb_mode_valid(struct drm_bridge *bridge,
>>>>>>  		   const struct drm_display_info *info,
>>>>>>  		   const struct drm_display_mode *mode)
>>>>>>  {
>>>>>> +	unsigned long link_freq, pclk_rate, rounded_pclk_rate;
>>>>>>  	struct fsl_ldb *fsl_ldb = to_fsl_ldb(bridge);
>>>>>>  
>>>>>>  	if (mode->clock > (fsl_ldb_is_dual(fsl_ldb) ? 160000 : 80000))
>>>>>>  		return MODE_CLOCK_HIGH;
>>>>>>  
>>>>>> +	/* Validate "ldb" clock rate. */
>>>>>> +	link_freq = fsl_ldb_link_frequency(fsl_ldb, mode->clock);
>>>>>> +	if (link_freq != clk_round_rate(fsl_ldb->clk, link_freq))
>>>>>> +		return MODE_NOCLOCK;
>>>>>> +
>>>>>> +	/*
>>>>>> +	 * Use "ldb" clock to validate pixel clock rate,
>>>>>> +	 * if the two clocks are sibling.
>>>>>> +	 */
>>>>>> +	if (fsl_ldb->devdata->ldb_clk_pixel_clk_sibling) {
>>>>>> +		pclk_rate = mode->clock * HZ_PER_KHZ;
>>>>>> +
>>>>>> +		rounded_pclk_rate = clk_round_rate(fsl_ldb->clk, pclk_rate);
>>>>>> +		if (rounded_pclk_rate != pclk_rate)
>>>>>> +			return MODE_NOCLOCK;
>>>>>> +	}
>>>>>> +
>>>>>
>>>>> I guess this is to workaround the fact that the parent rate would be
>>>>> changed, and thus the sibling rate as well? This should be documented in
>>>>> a comment if so.
>>>>
>>>> This is to workaround the fact that the display controller driver
>>>> (lcdif_kms.c) cannot do the mode validation against pixel clock, as
>>>> the commit message mentions.
>>>
>>> That part is still not super clear to me, but it's also not super
>>> important to the discussion.
>>
>> As kerneldoc of drm_crtc_helper_funcs::mode_valid mentions that
>> it is not allowed to look at anything else but the passed-in mode,
>> it doesn't know of the connected encoder(s)/bridge(s) and thus
>> cannot decide if it should do mode validation against pixel clock
>> or not.  Encoder/bridge drivers could adjust pixel clock rates
>> for display modes.  So, mode validation against pixel clock should
>> be done in this bridge driver.
>>
>> In fact, the pixel clock should have been defined as a DT property
>> in fsl,ldb.yaml because the clock routes to LDB as an input signal.
>> However, it's too late...  If the DT property was defined in the
>> first place, then this driver can naturally do mode validation
>> against pixel clock instead of this workaround.
>>
>>>
>>> My point is: from a clock API standpoint, there's absolutely no reason
>>> to consider sibling clocks. clk_round_rate() should give you the rate
>>
>> Agree, but it's a workaround.
>>
>>> you want. If it affects other clocks it shouldn't, it's a clock driver
>>> bug.
>>
>> The sibling clocks are the same type of clocks from HW design
>> point of view and derived from the same clock parent/PLL.
>> That's the reason why the workaround works.
>>
>>>
>>> You might want to workaround it, but this is definitely not something
>>> you should gloss over: it's a hack, it needs to be documented as such.
>>
>> I can add some documentation in next version to clarify this
>> a bit.
>>
>>>
>>>> The parent clock is IMX8MP_VIDEO_PLL1_OUT and it's clock rate is not
>>>> supposed to be changed any more once IMX8MP_VIDEO_PLL1 clock rate is
>>>> set by using DT assigned-clock-rates property.  For i.MX8MP EVK, the
>>>> clock rate is assigned to 1039500000Hz in imx8mp.dtsi in media_blk_ctrl
>>>> node.
>>>
>>> There's two things wrong with what you just described:
>>>
>>>   - assigned-clock-rates never provided the guarantee that the clock
>>>     rate wouldn't change later on. So if you rely on that, here's your
>>>     first bug.
>>
>> I'm not relying on that.
> 
> Sure you do. If anything in the kernel changes the rate of the
> VIDEO_PLL1 clock, then it's game over and "clock rate is not supposed to
> be changed any more once IMX8MP_VIDEO_PLL1 clock rate is set by using DT
> assigned-clock-rates property." isn't true anymore.

"clock rate is not supposed to be changed any more once IMX8MP_VIDEO_PLL1
clock rate is set by using DT assigned-clock-rates property." implies
that IMX8MP_VIDEO_PLL1 is used only by certain display pipelines as DT
writer can deliberately assign it as the parent clock of clocks like
display controller's pixel clock, which means nothing else in the
kernel would change the rate of the IMX8MP_VIDEO_PLL1 clock.

> 
>> Instead, the PLL clock rate is not supposed to change since
>> IMX8MP_CLK_MEDIA_LDB clock("ldb" clock parent clock) hasn't the
>> CLK_SET_RATE_PARENT flag. And, we don't want to change the PLL clock
>> rate at runtime because the PLL can be used by i.MX8MP MIPI DSI and
>> LDB display pipelines at the same time, driven by two LCDIFv3 display
>> controllers respectively with two imx-lcdif KMS instances. We don't
>> want to see the two display pipelines to step on each other.
>>
>>>
>>>   - If the parent clock rate must not change, why does that clock has
>>>     SET_RATE_PARENT then? Because that's the bug you're trying to work
>>>     around.
>>
>> IMX8MP_CLK_MEDIA_LDB clock hasn't the CLK_SET_RATE_PARENT flag.
>> I'm fine with the "ldb" clock tree from the current clock driver
>> PoV - just trying to validate pixel clock rate as a workaround.
> 
> As far as I can see, the ldb clock is IMX8MP_CLK_MEDIA_LDB_ROOT in
> imx8mp.dtsi. That clock is defined using imx_clk_hw_gate2_shared2 that
> does set CLK_SET_RATE_PARENT.

I said IMX8MP_CLK_MEDIA_LDB, not IMX8MP_CLK_MEDIA_LDB_ROOT.
IMX8MP_CLK_MEDIA_LDB clock is IMX8MP_CLK_MEDIA_LDB_ROOT clock's
parent clock.
IMX8MP_CLK_MEDIA_LDB clock hasn't the CLK_SET_RATE_PARENT flag.

IMX8MP_VIDEO_PLL1
  IMX8MP_VIDEO_PLL1_BYPASS
    IMX8MP_VIDEO_PLL1_OUT
      IMX8MP_CLK_MEDIA_LDB
        IMX8MP_CLK_MEDIA_LDB_ROOT  ->  "ldb" clock

> 
> Maxime

-- 
Regards,
Liu Ying


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

* [PATCH 3/8] drm/bridge: fsl-ldb: Get the next non-panel bridge
  2025-07-09 12:23 [PATCH 0/8] Add support for i.MX94 DCIF Laurentiu Palcu
@ 2025-07-09 12:23 ` Laurentiu Palcu
  2025-07-11  4:19   ` Frank Li
  0 siblings, 1 reply; 38+ messages in thread
From: Laurentiu Palcu @ 2025-07-09 12:23 UTC (permalink / raw)
  To: imx, Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter
  Cc: dri-devel, Liu Ying, Laurentiu Palcu, linux-kernel

From: Liu Ying <victor.liu@nxp.com>

The next bridge in bridge chain could be a panel bridge or a non-panel
bridge.  Use devm_drm_of_get_bridge() to replace the combination
function calls of of_drm_find_panel() and devm_drm_panel_bridge_add()
to get either a panel bridge or a non-panel bridge, instead of getting
a panel bridge only.

Signed-off-by: Liu Ying <victor.liu@nxp.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Signed-off-by: Laurentiu Palcu <laurentiu.palcu@oss.nxp.com>
---
 drivers/gpu/drm/bridge/fsl-ldb.c | 31 +++++++++++--------------------
 1 file changed, 11 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/bridge/fsl-ldb.c b/drivers/gpu/drm/bridge/fsl-ldb.c
index 5c3cf37200bce..665053d0cb79d 100644
--- a/drivers/gpu/drm/bridge/fsl-ldb.c
+++ b/drivers/gpu/drm/bridge/fsl-ldb.c
@@ -15,7 +15,6 @@
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_bridge.h>
 #include <drm/drm_of.h>
-#include <drm/drm_panel.h>
 
 #define LDB_CTRL_CH0_ENABLE			BIT(0)
 #define LDB_CTRL_CH0_DI_SELECT			BIT(1)
@@ -86,7 +85,7 @@ static const struct fsl_ldb_devdata fsl_ldb_devdata[] = {
 struct fsl_ldb {
 	struct device *dev;
 	struct drm_bridge bridge;
-	struct drm_bridge *panel_bridge;
+	struct drm_bridge *next_bridge;
 	struct clk *clk;
 	struct regmap *regmap;
 	const struct fsl_ldb_devdata *devdata;
@@ -118,7 +117,7 @@ static int fsl_ldb_attach(struct drm_bridge *bridge,
 {
 	struct fsl_ldb *fsl_ldb = to_fsl_ldb(bridge);
 
-	return drm_bridge_attach(encoder, fsl_ldb->panel_bridge,
+	return drm_bridge_attach(encoder, fsl_ldb->next_bridge,
 				 bridge, flags);
 }
 
@@ -292,9 +291,7 @@ static const struct drm_bridge_funcs funcs = {
 static int fsl_ldb_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
-	struct device_node *panel_node;
 	struct device_node *remote1, *remote2;
-	struct drm_panel *panel;
 	struct fsl_ldb *fsl_ldb;
 	int dual_link;
 
@@ -317,33 +314,27 @@ static int fsl_ldb_probe(struct platform_device *pdev)
 	if (IS_ERR(fsl_ldb->regmap))
 		return PTR_ERR(fsl_ldb->regmap);
 
-	/* Locate the remote ports and the panel node */
+	/* Locate the remote ports. */
 	remote1 = of_graph_get_remote_node(dev->of_node, 1, 0);
 	remote2 = of_graph_get_remote_node(dev->of_node, 2, 0);
 	fsl_ldb->ch0_enabled = (remote1 != NULL);
 	fsl_ldb->ch1_enabled = (remote2 != NULL);
-	panel_node = of_node_get(remote1 ? remote1 : remote2);
 	of_node_put(remote1);
 	of_node_put(remote2);
 
-	if (!fsl_ldb->ch0_enabled && !fsl_ldb->ch1_enabled) {
-		of_node_put(panel_node);
-		return dev_err_probe(dev, -ENXIO, "No panel node found");
-	}
+	if (!fsl_ldb->ch0_enabled && !fsl_ldb->ch1_enabled)
+		return dev_err_probe(dev, -ENXIO, "No next bridge node found");
 
 	dev_dbg(dev, "Using %s\n",
 		fsl_ldb_is_dual(fsl_ldb) ? "dual-link mode" :
 		fsl_ldb->ch0_enabled ? "channel 0" : "channel 1");
 
-	panel = of_drm_find_panel(panel_node);
-	of_node_put(panel_node);
-	if (IS_ERR(panel))
-		return PTR_ERR(panel);
-
-	fsl_ldb->panel_bridge = devm_drm_panel_bridge_add(dev, panel);
-	if (IS_ERR(fsl_ldb->panel_bridge))
-		return PTR_ERR(fsl_ldb->panel_bridge);
-
+	fsl_ldb->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node,
+						      fsl_ldb->ch0_enabled ? 1 : 2,
+						      0);
+	if (IS_ERR(fsl_ldb->next_bridge))
+		return dev_err_probe(dev, PTR_ERR(fsl_ldb->next_bridge),
+				     "failed to get next bridge\n");
 
 	if (fsl_ldb_is_dual(fsl_ldb)) {
 		struct device_node *port1, *port2;
-- 
2.46.1


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

* Re: [PATCH 3/8] drm/bridge: fsl-ldb: Get the next non-panel bridge
  2025-07-09 12:23 ` [PATCH 3/8] drm/bridge: fsl-ldb: Get the next non-panel bridge Laurentiu Palcu
@ 2025-07-11  4:19   ` Frank Li
  2025-07-11  5:31     ` Liu Ying
  0 siblings, 1 reply; 38+ messages in thread
From: Frank Li @ 2025-07-11  4:19 UTC (permalink / raw)
  To: Laurentiu Palcu
  Cc: imx, Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, dri-devel,
	Liu Ying, linux-kernel

On Wed, Jul 09, 2025 at 03:23:22PM +0300, Laurentiu Palcu wrote:
> From: Liu Ying <victor.liu@nxp.com>
>
> The next bridge in bridge chain could be a panel bridge or a non-panel
> bridge.  Use devm_drm_of_get_bridge() to replace the combination
         ^ extra space.

> function calls of of_drm_find_panel() and devm_drm_panel_bridge_add()
> to get either a panel bridge or a non-panel bridge, instead of getting
> a panel bridge only.

According to code change, devm_drm_of_get_bridge() replace
devm_drm_panel_bridge_add(of_drm_find_panel()).

what relationship with panel bridge or a non-panel bridge?

Frank

>
> Signed-off-by: Liu Ying <victor.liu@nxp.com>
> Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> Signed-off-by: Laurentiu Palcu <laurentiu.palcu@oss.nxp.com>
> ---
>  drivers/gpu/drm/bridge/fsl-ldb.c | 31 +++++++++++--------------------
>  1 file changed, 11 insertions(+), 20 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/fsl-ldb.c b/drivers/gpu/drm/bridge/fsl-ldb.c
> index 5c3cf37200bce..665053d0cb79d 100644
> --- a/drivers/gpu/drm/bridge/fsl-ldb.c
> +++ b/drivers/gpu/drm/bridge/fsl-ldb.c
> @@ -15,7 +15,6 @@
>  #include <drm/drm_atomic_helper.h>
>  #include <drm/drm_bridge.h>
>  #include <drm/drm_of.h>
> -#include <drm/drm_panel.h>
>
>  #define LDB_CTRL_CH0_ENABLE			BIT(0)
>  #define LDB_CTRL_CH0_DI_SELECT			BIT(1)
> @@ -86,7 +85,7 @@ static const struct fsl_ldb_devdata fsl_ldb_devdata[] = {
>  struct fsl_ldb {
>  	struct device *dev;
>  	struct drm_bridge bridge;
> -	struct drm_bridge *panel_bridge;
> +	struct drm_bridge *next_bridge;
>  	struct clk *clk;
>  	struct regmap *regmap;
>  	const struct fsl_ldb_devdata *devdata;
> @@ -118,7 +117,7 @@ static int fsl_ldb_attach(struct drm_bridge *bridge,
>  {
>  	struct fsl_ldb *fsl_ldb = to_fsl_ldb(bridge);
>
> -	return drm_bridge_attach(encoder, fsl_ldb->panel_bridge,
> +	return drm_bridge_attach(encoder, fsl_ldb->next_bridge,
>  				 bridge, flags);
>  }
>
> @@ -292,9 +291,7 @@ static const struct drm_bridge_funcs funcs = {
>  static int fsl_ldb_probe(struct platform_device *pdev)
>  {
>  	struct device *dev = &pdev->dev;
> -	struct device_node *panel_node;
>  	struct device_node *remote1, *remote2;
> -	struct drm_panel *panel;
>  	struct fsl_ldb *fsl_ldb;
>  	int dual_link;
>
> @@ -317,33 +314,27 @@ static int fsl_ldb_probe(struct platform_device *pdev)
>  	if (IS_ERR(fsl_ldb->regmap))
>  		return PTR_ERR(fsl_ldb->regmap);
>
> -	/* Locate the remote ports and the panel node */
> +	/* Locate the remote ports. */
>  	remote1 = of_graph_get_remote_node(dev->of_node, 1, 0);
>  	remote2 = of_graph_get_remote_node(dev->of_node, 2, 0);
>  	fsl_ldb->ch0_enabled = (remote1 != NULL);
>  	fsl_ldb->ch1_enabled = (remote2 != NULL);
> -	panel_node = of_node_get(remote1 ? remote1 : remote2);
>  	of_node_put(remote1);
>  	of_node_put(remote2);
>
> -	if (!fsl_ldb->ch0_enabled && !fsl_ldb->ch1_enabled) {
> -		of_node_put(panel_node);
> -		return dev_err_probe(dev, -ENXIO, "No panel node found");
> -	}
> +	if (!fsl_ldb->ch0_enabled && !fsl_ldb->ch1_enabled)
> +		return dev_err_probe(dev, -ENXIO, "No next bridge node found");
>
>  	dev_dbg(dev, "Using %s\n",
>  		fsl_ldb_is_dual(fsl_ldb) ? "dual-link mode" :
>  		fsl_ldb->ch0_enabled ? "channel 0" : "channel 1");
>
> -	panel = of_drm_find_panel(panel_node);
> -	of_node_put(panel_node);
> -	if (IS_ERR(panel))
> -		return PTR_ERR(panel);
> -
> -	fsl_ldb->panel_bridge = devm_drm_panel_bridge_add(dev, panel);
> -	if (IS_ERR(fsl_ldb->panel_bridge))
> -		return PTR_ERR(fsl_ldb->panel_bridge);
> -
> +	fsl_ldb->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node,
> +						      fsl_ldb->ch0_enabled ? 1 : 2,
> +						      0);
> +	if (IS_ERR(fsl_ldb->next_bridge))
> +		return dev_err_probe(dev, PTR_ERR(fsl_ldb->next_bridge),
> +				     "failed to get next bridge\n");
>
>  	if (fsl_ldb_is_dual(fsl_ldb)) {
>  		struct device_node *port1, *port2;
> --
> 2.46.1
>

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

* Re: [PATCH 3/8] drm/bridge: fsl-ldb: Get the next non-panel bridge
  2025-07-11  4:19   ` Frank Li
@ 2025-07-11  5:31     ` Liu Ying
  0 siblings, 0 replies; 38+ messages in thread
From: Liu Ying @ 2025-07-11  5:31 UTC (permalink / raw)
  To: Frank Li, Laurentiu Palcu
  Cc: imx, Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, dri-devel,
	linux-kernel

On 07/11/2025, Frank Li wrote:
> On Wed, Jul 09, 2025 at 03:23:22PM +0300, Laurentiu Palcu wrote:
>> From: Liu Ying <victor.liu@nxp.com>
>>
>> The next bridge in bridge chain could be a panel bridge or a non-panel
>> bridge.  Use devm_drm_of_get_bridge() to replace the combination
>          ^ extra space.

It's intentional for readers to be aware of the start of a next sentence
easily.  It's not uncommon in kernel commit messages.

> 
>> function calls of of_drm_find_panel() and devm_drm_panel_bridge_add()
>> to get either a panel bridge or a non-panel bridge, instead of getting
>> a panel bridge only.
> 
> According to code change, devm_drm_of_get_bridge() replace
> devm_drm_panel_bridge_add(of_drm_find_panel()).
> 
> what relationship with panel bridge or a non-panel bridge?

Here, the former represents a panel with only video sink, and the latter
represents a bridge with both video sink and video source.

> 
> Frank
> 
>>
>> Signed-off-by: Liu Ying <victor.liu@nxp.com>
>> Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>> Signed-off-by: Laurentiu Palcu <laurentiu.palcu@oss.nxp.com>
>> ---
>>  drivers/gpu/drm/bridge/fsl-ldb.c | 31 +++++++++++--------------------
>>  1 file changed, 11 insertions(+), 20 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/bridge/fsl-ldb.c b/drivers/gpu/drm/bridge/fsl-ldb.c
>> index 5c3cf37200bce..665053d0cb79d 100644
>> --- a/drivers/gpu/drm/bridge/fsl-ldb.c
>> +++ b/drivers/gpu/drm/bridge/fsl-ldb.c
>> @@ -15,7 +15,6 @@
>>  #include <drm/drm_atomic_helper.h>
>>  #include <drm/drm_bridge.h>
>>  #include <drm/drm_of.h>
>> -#include <drm/drm_panel.h>
>>
>>  #define LDB_CTRL_CH0_ENABLE			BIT(0)
>>  #define LDB_CTRL_CH0_DI_SELECT			BIT(1)
>> @@ -86,7 +85,7 @@ static const struct fsl_ldb_devdata fsl_ldb_devdata[] = {
>>  struct fsl_ldb {
>>  	struct device *dev;
>>  	struct drm_bridge bridge;
>> -	struct drm_bridge *panel_bridge;
>> +	struct drm_bridge *next_bridge;
>>  	struct clk *clk;
>>  	struct regmap *regmap;
>>  	const struct fsl_ldb_devdata *devdata;
>> @@ -118,7 +117,7 @@ static int fsl_ldb_attach(struct drm_bridge *bridge,
>>  {
>>  	struct fsl_ldb *fsl_ldb = to_fsl_ldb(bridge);
>>
>> -	return drm_bridge_attach(encoder, fsl_ldb->panel_bridge,
>> +	return drm_bridge_attach(encoder, fsl_ldb->next_bridge,
>>  				 bridge, flags);
>>  }
>>
>> @@ -292,9 +291,7 @@ static const struct drm_bridge_funcs funcs = {
>>  static int fsl_ldb_probe(struct platform_device *pdev)
>>  {
>>  	struct device *dev = &pdev->dev;
>> -	struct device_node *panel_node;
>>  	struct device_node *remote1, *remote2;
>> -	struct drm_panel *panel;
>>  	struct fsl_ldb *fsl_ldb;
>>  	int dual_link;
>>
>> @@ -317,33 +314,27 @@ static int fsl_ldb_probe(struct platform_device *pdev)
>>  	if (IS_ERR(fsl_ldb->regmap))
>>  		return PTR_ERR(fsl_ldb->regmap);
>>
>> -	/* Locate the remote ports and the panel node */
>> +	/* Locate the remote ports. */
>>  	remote1 = of_graph_get_remote_node(dev->of_node, 1, 0);
>>  	remote2 = of_graph_get_remote_node(dev->of_node, 2, 0);
>>  	fsl_ldb->ch0_enabled = (remote1 != NULL);
>>  	fsl_ldb->ch1_enabled = (remote2 != NULL);
>> -	panel_node = of_node_get(remote1 ? remote1 : remote2);
>>  	of_node_put(remote1);
>>  	of_node_put(remote2);
>>
>> -	if (!fsl_ldb->ch0_enabled && !fsl_ldb->ch1_enabled) {
>> -		of_node_put(panel_node);
>> -		return dev_err_probe(dev, -ENXIO, "No panel node found");
>> -	}
>> +	if (!fsl_ldb->ch0_enabled && !fsl_ldb->ch1_enabled)
>> +		return dev_err_probe(dev, -ENXIO, "No next bridge node found");
>>
>>  	dev_dbg(dev, "Using %s\n",
>>  		fsl_ldb_is_dual(fsl_ldb) ? "dual-link mode" :
>>  		fsl_ldb->ch0_enabled ? "channel 0" : "channel 1");
>>
>> -	panel = of_drm_find_panel(panel_node);
>> -	of_node_put(panel_node);
>> -	if (IS_ERR(panel))
>> -		return PTR_ERR(panel);
>> -
>> -	fsl_ldb->panel_bridge = devm_drm_panel_bridge_add(dev, panel);
>> -	if (IS_ERR(fsl_ldb->panel_bridge))
>> -		return PTR_ERR(fsl_ldb->panel_bridge);
>> -
>> +	fsl_ldb->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node,
>> +						      fsl_ldb->ch0_enabled ? 1 : 2,
>> +						      0);
>> +	if (IS_ERR(fsl_ldb->next_bridge))
>> +		return dev_err_probe(dev, PTR_ERR(fsl_ldb->next_bridge),
>> +				     "failed to get next bridge\n");
>>
>>  	if (fsl_ldb_is_dual(fsl_ldb)) {
>>  		struct device_node *port1, *port2;
>> --
>> 2.46.1
>>

-- 
Regards,
Liu Ying

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

end of thread, other threads:[~2025-07-11  5:30 UTC | newest]

Thread overview: 38+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-09-30  5:28 [PATCH 0/8] Add ITE IT6263 LVDS to HDMI converter support Liu Ying
2024-09-30  5:28 ` [PATCH 1/8] arm64: dts: imx8mp-skov-revb-mi1010ait-1cp1: Add panel-timing node to panel node Liu Ying
2024-09-30  5:28 ` [PATCH 2/8] arm64: dts: imx8mp-phyboard-pollux-rdk: Add panel-timing node to panel-lvds node Liu Ying
2024-09-30  5:28 ` [PATCH 3/8] drm/bridge: fsl-ldb: Get the next non-panel bridge Liu Ying
2024-09-30  5:28 ` [PATCH 4/8] drm/bridge: fsl-ldb: Use clk_round_rate() to validate "ldb" clock rate Liu Ying
2024-09-30  7:31   ` Maxime Ripard
2024-09-30  7:55     ` Liu Ying
2024-10-11 11:06       ` Maxime Ripard
2024-10-12  6:18         ` Liu Ying
2024-10-14  9:22           ` Maxime Ripard
2024-10-14  9:40             ` Liu Ying
2024-09-30  5:29 ` [PATCH 5/8] dt-bindings: display: bridge: Add ITE IT6263 LVDS to HDMI converter Liu Ying
2024-09-30  9:04   ` Biju Das
2024-09-30  9:16     ` Liu Ying
2024-09-30  9:24       ` Biju Das
2024-09-30  9:30         ` Liu Ying
2024-09-30  9:38           ` Biju Das
2024-09-30  9:48             ` Liu Ying
2024-09-30  9:53               ` Biju Das
2024-09-30 13:18     ` Biju Das
2024-10-09  7:51       ` Liu Ying
2024-10-02  0:02   ` Rob Herring
2024-10-09  7:00     ` Liu Ying
2024-09-30  5:29 ` [PATCH 6/8] drm/bridge: " Liu Ying
2024-09-30  7:11   ` Maxime Ripard
2024-09-30  8:44     ` Liu Ying
2024-09-30  9:16   ` Biju Das
2024-09-30  9:40     ` Liu Ying
2024-09-30  9:45       ` Biju Das
2024-09-30 13:10     ` Biju Das
2024-10-09  8:33       ` Liu Ying
2024-10-09 17:02         ` Dmitry Baryshkov
2024-10-02 10:19   ` Biju Das
2024-09-30  5:29 ` [PATCH 7/8] arm64: dts: imx8mp-evk: Add NXP LVDS to HDMI adapter cards Liu Ying
2024-09-30  5:29 ` [PATCH 8/8] arm64: defconfig: Enable ITE IT6263 driver Liu Ying
  -- strict thread matches above, loose matches on Subject: below --
2025-07-09 12:23 [PATCH 0/8] Add support for i.MX94 DCIF Laurentiu Palcu
2025-07-09 12:23 ` [PATCH 3/8] drm/bridge: fsl-ldb: Get the next non-panel bridge Laurentiu Palcu
2025-07-11  4:19   ` Frank Li
2025-07-11  5:31     ` Liu Ying

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