* [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; 35+ 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] 35+ 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; 35+ 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 = <®_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] 35+ 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; 35+ 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 = <®_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] 35+ 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; 35+ 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] 35+ 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; 35+ 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] 35+ 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; 35+ 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 = <®_buck5>;
+ ovdd-supply = <®_vext_3v3>;
+ txavcc18-supply = <®_buck5>;
+ txavcc33-supply = <®_vext_3v3>;
+ pvcc1-supply = <®_buck5>;
+ pvcc2-supply = <®_buck5>;
+ avcc-supply = <®_vext_3v3>;
+ anvdd-supply = <®_buck5>;
+ apvdd-supply = <®_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 = <®_buck5>;
+ ovdd-supply = <®_vext_3v3>;
+ txavcc18-supply = <®_buck5>;
+ txavcc33-supply = <®_vext_3v3>;
+ pvcc1-supply = <®_buck5>;
+ pvcc2-supply = <®_buck5>;
+ avcc-supply = <®_vext_3v3>;
+ anvdd-supply = <®_buck5>;
+ apvdd-supply = <®_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] 35+ 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; 35+ 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] 35+ 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; 35+ 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 = <®_buck5>;
+ ovdd-supply = <®_vext_3v3>;
+ txavcc18-supply = <®_buck5>;
+ txavcc33-supply = <®_vext_3v3>;
+ pvcc1-supply = <®_buck5>;
+ pvcc2-supply = <®_buck5>;
+ avcc-supply = <®_vext_3v3>;
+ anvdd-supply = <®_buck5>;
+ apvdd-supply = <®_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 = <®_buck5>;
+ ovdd-supply = <®_vext_3v3>;
+ txavcc18-supply = <®_buck5>;
+ txavcc33-supply = <®_vext_3v3>;
+ pvcc1-supply = <®_buck5>;
+ pvcc2-supply = <®_buck5>;
+ avcc-supply = <®_vext_3v3>;
+ anvdd-supply = <®_buck5>;
+ apvdd-supply = <®_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] 35+ 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; 35+ 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] 35+ 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; 35+ 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] 35+ 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; 35+ 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] 35+ 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; 35+ 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] 35+ 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; 35+ 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] 35+ 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; 35+ 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 = <®_buck5>;
> + ovdd-supply = <®_vext_3v3>;
> + txavcc18-supply = <®_buck5>;
> + txavcc33-supply = <®_vext_3v3>;
> + pvcc1-supply = <®_buck5>;
> + pvcc2-supply = <®_buck5>;
> + avcc-supply = <®_vext_3v3>;
> + anvdd-supply = <®_buck5>;
> + apvdd-supply = <®_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 = <®_buck5>;
> + ovdd-supply = <®_vext_3v3>;
> + txavcc18-supply = <®_buck5>;
> + txavcc33-supply = <®_vext_3v3>;
> + pvcc1-supply = <®_buck5>;
> + pvcc2-supply = <®_buck5>;
> + avcc-supply = <®_vext_3v3>;
> + anvdd-supply = <®_buck5>;
> + apvdd-supply = <®_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] 35+ 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; 35+ 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 = <®_buck5>;
>> + ovdd-supply = <®_vext_3v3>;
>> + txavcc18-supply = <®_buck5>;
>> + txavcc33-supply = <®_vext_3v3>;
>> + pvcc1-supply = <®_buck5>;
>> + pvcc2-supply = <®_buck5>;
>> + avcc-supply = <®_vext_3v3>;
>> + anvdd-supply = <®_buck5>;
>> + apvdd-supply = <®_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 = <®_buck5>;
>> + ovdd-supply = <®_vext_3v3>;
>> + txavcc18-supply = <®_buck5>;
>> + txavcc33-supply = <®_vext_3v3>;
>> + pvcc1-supply = <®_buck5>;
>> + pvcc2-supply = <®_buck5>;
>> + avcc-supply = <®_vext_3v3>;
>> + anvdd-supply = <®_buck5>;
>> + apvdd-supply = <®_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] 35+ 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; 35+ 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] 35+ 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; 35+ 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 = <®_buck5>;
> >> + ovdd-supply = <®_vext_3v3>;
> >> + txavcc18-supply = <®_buck5>;
> >> + txavcc33-supply = <®_vext_3v3>;
> >> + pvcc1-supply = <®_buck5>;
> >> + pvcc2-supply = <®_buck5>;
> >> + avcc-supply = <®_vext_3v3>;
> >> + anvdd-supply = <®_buck5>;
> >> + apvdd-supply = <®_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 = <®_buck5>;
> >> + ovdd-supply = <®_vext_3v3>;
> >> + txavcc18-supply = <®_buck5>;
> >> + txavcc33-supply = <®_vext_3v3>;
> >> + pvcc1-supply = <®_buck5>;
> >> + pvcc2-supply = <®_buck5>;
> >> + avcc-supply = <®_vext_3v3>;
> >> + anvdd-supply = <®_buck5>;
> >> + apvdd-supply = <®_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] 35+ 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; 35+ 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 = <®_buck5>;
>>>> + ovdd-supply = <®_vext_3v3>;
>>>> + txavcc18-supply = <®_buck5>;
>>>> + txavcc33-supply = <®_vext_3v3>;
>>>> + pvcc1-supply = <®_buck5>;
>>>> + pvcc2-supply = <®_buck5>;
>>>> + avcc-supply = <®_vext_3v3>;
>>>> + anvdd-supply = <®_buck5>;
>>>> + apvdd-supply = <®_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 = <®_buck5>;
>>>> + ovdd-supply = <®_vext_3v3>;
>>>> + txavcc18-supply = <®_buck5>;
>>>> + txavcc33-supply = <®_vext_3v3>;
>>>> + pvcc1-supply = <®_buck5>;
>>>> + pvcc2-supply = <®_buck5>;
>>>> + avcc-supply = <®_vext_3v3>;
>>>> + anvdd-supply = <®_buck5>;
>>>> + apvdd-supply = <®_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] 35+ 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; 35+ 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 = <®_buck5>;
> >>>> + ovdd-supply = <®_vext_3v3>;
> >>>> + txavcc18-supply = <®_buck5>;
> >>>> + txavcc33-supply = <®_vext_3v3>;
> >>>> + pvcc1-supply = <®_buck5>;
> >>>> + pvcc2-supply = <®_buck5>;
> >>>> + avcc-supply = <®_vext_3v3>;
> >>>> + anvdd-supply = <®_buck5>;
> >>>> + apvdd-supply = <®_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 = <®_buck5>;
> >>>> + ovdd-supply = <®_vext_3v3>;
> >>>> + txavcc18-supply = <®_buck5>;
> >>>> + txavcc33-supply = <®_vext_3v3>;
> >>>> + pvcc1-supply = <®_buck5>;
> >>>> + pvcc2-supply = <®_buck5>;
> >>>> + avcc-supply = <®_vext_3v3>;
> >>>> + anvdd-supply = <®_buck5>;
> >>>> + apvdd-supply = <®_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] 35+ 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; 35+ 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] 35+ 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; 35+ 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] 35+ 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; 35+ 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 = <®_buck5>;
>>>>>> + ovdd-supply = <®_vext_3v3>;
>>>>>> + txavcc18-supply = <®_buck5>;
>>>>>> + txavcc33-supply = <®_vext_3v3>;
>>>>>> + pvcc1-supply = <®_buck5>;
>>>>>> + pvcc2-supply = <®_buck5>;
>>>>>> + avcc-supply = <®_vext_3v3>;
>>>>>> + anvdd-supply = <®_buck5>;
>>>>>> + apvdd-supply = <®_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 = <®_buck5>;
>>>>>> + ovdd-supply = <®_vext_3v3>;
>>>>>> + txavcc18-supply = <®_buck5>;
>>>>>> + txavcc33-supply = <®_vext_3v3>;
>>>>>> + pvcc1-supply = <®_buck5>;
>>>>>> + pvcc2-supply = <®_buck5>;
>>>>>> + avcc-supply = <®_vext_3v3>;
>>>>>> + anvdd-supply = <®_buck5>;
>>>>>> + apvdd-supply = <®_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] 35+ 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; 35+ 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 = <®_buck5>;
> >>>>>> + ovdd-supply = <®_vext_3v3>;
> >>>>>> + txavcc18-supply = <®_buck5>;
> >>>>>> + txavcc33-supply = <®_vext_3v3>;
> >>>>>> + pvcc1-supply = <®_buck5>;
> >>>>>> + pvcc2-supply = <®_buck5>;
> >>>>>> + avcc-supply = <®_vext_3v3>;
> >>>>>> + anvdd-supply = <®_buck5>;
> >>>>>> + apvdd-supply = <®_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 = <®_buck5>;
> >>>>>> + ovdd-supply = <®_vext_3v3>;
> >>>>>> + txavcc18-supply = <®_buck5>;
> >>>>>> + txavcc33-supply = <®_vext_3v3>;
> >>>>>> + pvcc1-supply = <®_buck5>;
> >>>>>> + pvcc2-supply = <®_buck5>;
> >>>>>> + avcc-supply = <®_vext_3v3>;
> >>>>>> + anvdd-supply = <®_buck5>;
> >>>>>> + apvdd-supply = <®_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] 35+ 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; 35+ 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] 35+ 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; 35+ 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 = <®_buck5>;
> > + ovdd-supply = <®_vext_3v3>;
> > + txavcc18-supply = <®_buck5>;
> > + txavcc33-supply = <®_vext_3v3>;
> > + pvcc1-supply = <®_buck5>;
> > + pvcc2-supply = <®_buck5>;
> > + avcc-supply = <®_vext_3v3>;
> > + anvdd-supply = <®_buck5>;
> > + apvdd-supply = <®_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 = <®_buck5>;
> > + ovdd-supply = <®_vext_3v3>;
> > + txavcc18-supply = <®_buck5>;
> > + txavcc33-supply = <®_vext_3v3>;
> > + pvcc1-supply = <®_buck5>;
> > + pvcc2-supply = <®_buck5>;
> > + avcc-supply = <®_vext_3v3>;
> > + anvdd-supply = <®_buck5>;
> > + apvdd-supply = <®_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] 35+ 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; 35+ 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] 35+ 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; 35+ 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] 35+ 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; 35+ 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] 35+ 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; 35+ 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 = <®_buck5>;
>>> + ovdd-supply = <®_vext_3v3>;
>>> + txavcc18-supply = <®_buck5>;
>>> + txavcc33-supply = <®_vext_3v3>;
>>> + pvcc1-supply = <®_buck5>;
>>> + pvcc2-supply = <®_buck5>;
>>> + avcc-supply = <®_vext_3v3>;
>>> + anvdd-supply = <®_buck5>;
>>> + apvdd-supply = <®_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 = <®_buck5>;
>>> + ovdd-supply = <®_vext_3v3>;
>>> + txavcc18-supply = <®_buck5>;
>>> + txavcc33-supply = <®_vext_3v3>;
>>> + pvcc1-supply = <®_buck5>;
>>> + pvcc2-supply = <®_buck5>;
>>> + avcc-supply = <®_vext_3v3>;
>>> + anvdd-supply = <®_buck5>;
>>> + apvdd-supply = <®_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] 35+ 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; 35+ 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] 35+ 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; 35+ 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] 35+ 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; 35+ 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] 35+ 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; 35+ 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] 35+ 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; 35+ 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] 35+ 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; 35+ 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] 35+ messages in thread
end of thread, other threads:[~2024-10-14 9:40 UTC | newest]
Thread overview: 35+ 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
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).