From f6882fa104d96447f0b9e4e881712e456b67f0f4 Mon Sep 17 00:00:00 2001 From: Salendarsingh Gaud Date: Mon, 13 Jul 2026 21:05:49 +0530 Subject: [PATCH 01/14] Revert "FROMLIST: arm64: defconfig: Enable LT9611C bridge driver" Commit is NAKed in upstream, so reverting for now. This reverts commit 2f074adbd0574c7565653cf5ab061a7c58ff99ee. Signed-off-by: Salendarsingh Gaud --- arch/arm64/configs/defconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 3d2a0d9ff865c..f616dd6ae116e 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -971,7 +971,6 @@ CONFIG_DRM_LONTIUM_LT8713SX=m CONFIG_DRM_LONTIUM_LT8912B=m CONFIG_DRM_LONTIUM_LT9211=m CONFIG_DRM_LONTIUM_LT9611=m -CONFIG_DRM_LONTIUM_LT9611C=m CONFIG_DRM_LONTIUM_LT9611UXC=m CONFIG_DRM_ITE_IT66121=m CONFIG_DRM_NWL_MIPI_DSI=m From 7f5c8de28e1f9f2b2215fb25286fe6f646e79231 Mon Sep 17 00:00:00 2001 From: Salendarsingh Gaud Date: Mon, 13 Jul 2026 21:05:56 +0530 Subject: [PATCH 02/14] Revert "FROMLIST: drm/bridge: lt9611c: clean up probe error and remove paths" Commit is NAKed in upstream, so reverting for now. This reverts commit 1a9b2e035afd6845cfa6f953c71a83d60ecad5c2. Signed-off-by: Salendarsingh Gaud --- drivers/gpu/drm/bridge/lontium-lt9611c.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/bridge/lontium-lt9611c.c b/drivers/gpu/drm/bridge/lontium-lt9611c.c index 30828bb9b3b85..d35a246e2d011 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611c.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611c.c @@ -1234,7 +1234,9 @@ static int lt9611c_probe(struct i2c_client *client) return 0; err_remove_bridge: + free_irq(client->irq, lt9611c); cancel_work_sync(<9611c->work); + drm_bridge_remove(<9611c->bridge); err_disable_regulators: regulator_bulk_disable(ARRAY_SIZE(lt9611c->supplies), lt9611c->supplies); @@ -1250,6 +1252,7 @@ static void lt9611c_remove(struct i2c_client *client) { struct lt9611c *lt9611c = i2c_get_clientdata(client); + free_irq(client->irq, lt9611c); cancel_work_sync(<9611c->work); regulator_bulk_disable(ARRAY_SIZE(lt9611c->supplies), lt9611c->supplies); of_node_put(lt9611c->dsi1_node); From b2a91ca1f09be2f5f9a3df8f0d6ae8fdef758cf5 Mon Sep 17 00:00:00 2001 From: Salendarsingh Gaud Date: Mon, 13 Jul 2026 21:05:56 +0530 Subject: [PATCH 03/14] Revert "FROMLIST: drm/bridge: lt9611c: fix chip type initialization" Commit is NAKed in upstream, so reverting for now. This reverts commit ec012bfaa5947bc61703133d1ec7144256a23c80. Signed-off-by: Salendarsingh Gaud --- drivers/gpu/drm/bridge/lontium-lt9611c.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/bridge/lontium-lt9611c.c b/drivers/gpu/drm/bridge/lontium-lt9611c.c index d35a246e2d011..4c8a3829a4bed 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611c.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611c.c @@ -1105,6 +1105,7 @@ static int lt9611c_probe(struct i2c_client *client) lt9611c->dev = dev; lt9611c->client = client; + lt9611c->chip_type = id->driver_data; if (dev->of_node) { lt9611c->chip_type = (uintptr_t)of_device_get_match_data(dev); From 77ba6a010a6556a4434c3723b5bcaff9d18c7591 Mon Sep 17 00:00:00 2001 From: Salendarsingh Gaud Date: Mon, 13 Jul 2026 21:05:56 +0530 Subject: [PATCH 04/14] Revert "FROMLIST: drm/bridge: lt9611c: fix DT parsing and bridge refcount" Commit is NAKed in upstream, so reverting for now. This reverts commit e4d89a3c2de8b93ac3de9247a31923db334866dd. Signed-off-by: Salendarsingh Gaud --- drivers/gpu/drm/bridge/lontium-lt9611c.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/gpu/drm/bridge/lontium-lt9611c.c b/drivers/gpu/drm/bridge/lontium-lt9611c.c index 4c8a3829a4bed..30a07e97626aa 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611c.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611c.c @@ -974,8 +974,6 @@ static const struct drm_bridge_funcs lt9611c_bridge_funcs = { static int lt9611c_parse_dt(struct device *dev, struct lt9611c *lt9611c) { - int ret; - lt9611c->dsi0_node = of_graph_get_remote_node(dev->of_node, 0, -1); if (!lt9611c->dsi0_node) return dev_err_probe(dev, -ENODEV, "failed to get remote node for primary dsi\n"); @@ -986,14 +984,7 @@ static int lt9611c_parse_dt(struct device *dev, <9611c->selected_port)) lt9611c->selected_port = 0; - ret = drm_of_find_panel_or_bridge(dev->of_node, 2, -1, NULL, <9611c->bridge.next_bridge); - if (ret) { - of_node_put(lt9611c->dsi1_node); - of_node_put(lt9611c->dsi0_node); - return ret; - } - drm_bridge_get(lt9611c->bridge.next_bridge); - return 0; + return drm_of_find_panel_or_bridge(dev->of_node, 2, -1, NULL, <9611c->bridge.next_bridge); } static int lt9611c_gpio_init(struct lt9611c *lt9611c) From 5c905cbdf604b581a3809afbb256224b02de0f90 Mon Sep 17 00:00:00 2001 From: Salendarsingh Gaud Date: Mon, 13 Jul 2026 21:05:56 +0530 Subject: [PATCH 05/14] Revert "FROMLIST: drm/bridge: lt9611c: implement hpd_enable callback" Commit is NAKed in upstream, so reverting for now. This reverts commit f28f9a08ae61720c0672609e09e7a4c61b18fe70. Signed-off-by: Salendarsingh Gaud --- drivers/gpu/drm/bridge/lontium-lt9611c.c | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/drivers/gpu/drm/bridge/lontium-lt9611c.c b/drivers/gpu/drm/bridge/lontium-lt9611c.c index 30a07e97626aa..81ca9d62eae37 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611c.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611c.c @@ -923,23 +923,6 @@ static void lt9611c_hdmi_audio_shutdown(struct drm_bridge *bridge, drm_atomic_helper_connector_hdmi_clear_audio_infoframe(connector); } -static void lt9611c_bridge_hpd_enable(struct drm_bridge *bridge) -{ - struct lt9611c *lt9611c = bridge_to_lt9611c(bridge); - u8 cmd[5] = {0x52, 0x48, 0x31, 0x3a, 0x00}; - u8 data[5]; - int ret; - - mutex_lock(<9611c->ocm_lock); - ret = lt9611c_read_write_flow(lt9611c, cmd, ARRAY_SIZE(cmd), - data, ARRAY_SIZE(data)); - if (!ret) - lt9611c->hdmi_connected = (data[4] == 0x02); - mutex_unlock(<9611c->ocm_lock); - - schedule_work(<9611c->work); -} - static int lt9611c_hdmi_audio_startup(struct drm_bridge *bridge, struct drm_connector *connector) { @@ -956,7 +939,6 @@ static const struct drm_bridge_funcs lt9611c_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, - .hpd_enable = lt9611c_bridge_hpd_enable, .hdmi_tmds_char_rate_valid = lt9611c_hdmi_tmds_char_rate_valid, .hdmi_write_avi_infoframe = lt9611c_hdmi_write_avi_infoframe, From 29c42412542a8c023a690fecc282fede31f8763c Mon Sep 17 00:00:00 2001 From: Salendarsingh Gaud Date: Mon, 13 Jul 2026 21:05:57 +0530 Subject: [PATCH 06/14] Revert "FROMLIST: drm/bridge: lt9611c: fallback to cached HPD status on read failure" Commit is NAKed in upstream, so reverting for now. This reverts commit 87dab5ed4da5fb4deb6b428f025792e9715ea1f6. Signed-off-by: Salendarsingh Gaud --- drivers/gpu/drm/bridge/lontium-lt9611c.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/lontium-lt9611c.c b/drivers/gpu/drm/bridge/lontium-lt9611c.c index 81ca9d62eae37..5d67bb7391fb8 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611c.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611c.c @@ -711,12 +711,10 @@ lt9611c_bridge_detect(struct drm_bridge *bridge, struct drm_connector *connector guard(mutex)(<9611c->ocm_lock); ret = lt9611c_read_write_flow(lt9611c, cmd, ARRAY_SIZE(cmd), data, ARRAY_SIZE(data)); - if (ret) { + if (ret) dev_err(dev, "failed to read HPD status (err=%d)\n", ret); - connected = lt9611c->hdmi_connected; - } else { + else connected = (data[4] == 0x02); - } lt9611c->hdmi_connected = connected; From a106c5bcbb0ad3726b3ebe7665925493e1771048 Mon Sep 17 00:00:00 2001 From: Salendarsingh Gaud Date: Mon, 13 Jul 2026 21:05:57 +0530 Subject: [PATCH 07/14] Revert "FROMLIST: drm/bridge: lontium-lt9611c: Add DSI port selection via DT property" Commit is NAKed in upstream, so reverting for now. This reverts commit 71083791536fb774d4ef4341c0e97daf599436ec. Signed-off-by: Salendarsingh Gaud --- drivers/gpu/drm/bridge/lontium-lt9611c.c | 44 ------------------------ 1 file changed, 44 deletions(-) diff --git a/drivers/gpu/drm/bridge/lontium-lt9611c.c b/drivers/gpu/drm/bridge/lontium-lt9611c.c index 5d67bb7391fb8..fe51f49785460 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611c.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611c.c @@ -41,12 +41,6 @@ enum lt9611_chip_type { CHIP_LT9611UXD, }; -enum lt9611c_PORT_SELECT { - PORT_SELECT_A = 0, - PORT_SELECT_B = 1, - PORT_SELECT_AB = 2, -}; - struct lt9611c { struct device *dev; struct i2c_client *client; @@ -66,8 +60,6 @@ struct lt9611c { enum lt9611_chip_type chip_type; /* HDMI cable connection status */ bool hdmi_connected; - /* Selected DSI port configuration */ - int selected_port; }; DECLARE_CRC8_TABLE(lt9611c_crc8_table); @@ -123,34 +115,6 @@ static int lt9611c_read_write_flow(struct lt9611c *lt9611c, u8 *params, return_count); } -static int lt9611c_select_port(struct lt9611c *lt9611c, int port_select) -{ - int ret; - u8 set_port_select_cmd[6] = {0x57, 0x4d, 0x31, 0x3a, 0x01, 0xc0}; - u8 set_port_select_ret[5]; - - if (port_select == PORT_SELECT_B) { - set_port_select_cmd[5] = 0x40; - } else if (port_select == PORT_SELECT_AB) { - set_port_select_cmd[4] = 0x02; - set_port_select_cmd[5] = 0xd0; - } else if (port_select != PORT_SELECT_A) { - return -EINVAL; - } - - /* MCU must be running (0xe0ee=0x00) for lt9611c_read_write_flow */ - guard(mutex)(<9611c->ocm_lock); - - ret = lt9611c_read_write_flow(lt9611c, set_port_select_cmd, - ARRAY_SIZE(set_port_select_cmd), - set_port_select_ret, - ARRAY_SIZE(set_port_select_ret)); - if (ret < 0 || set_port_select_ret[4] == 0) - return ret < 0 ? ret : -EIO; - - return 0; -} - static void lt9611c_config_parameters(struct lt9611c *lt9611c) { const struct reg_sequence seq_write_paras[] = { @@ -960,10 +924,6 @@ static int lt9611c_parse_dt(struct device *dev, lt9611c->dsi1_node = of_graph_get_remote_node(dev->of_node, 1, -1); - if (of_property_read_u32(dev->of_node, "lontium,port-select", - <9611c->selected_port)) - lt9611c->selected_port = 0; - return drm_of_find_panel_or_bridge(dev->of_node, 2, -1, NULL, <9611c->bridge.next_bridge); } @@ -1110,10 +1070,6 @@ static int lt9611c_probe(struct i2c_client *client) lt9611c_reset(lt9611c); - ret = lt9611c_select_port(lt9611c, lt9611c->selected_port); - if (ret < 0) - dev_err(lt9611c->dev, "failed to select port %d\n", lt9611c->selected_port); - lt9611c_lock(lt9611c); ret = lt9611c_read_chipid(lt9611c); From 94d580a42961b13f960ca7dd313bf4aadce8e8cd Mon Sep 17 00:00:00 2001 From: Salendarsingh Gaud Date: Mon, 13 Jul 2026 21:05:57 +0530 Subject: [PATCH 08/14] Revert "FROMLIST: drm-bridge: lontium lt9611c: fixes and improvements" Commit is NAKed in upstream, so reverting for now. This reverts commit 4c28ed940c3490c223c394a503131cbb63350e13. Signed-off-by: Salendarsingh Gaud --- drivers/gpu/drm/bridge/lontium-lt9611c.c | 31 ++++-------------------- 1 file changed, 5 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/bridge/lontium-lt9611c.c b/drivers/gpu/drm/bridge/lontium-lt9611c.c index fe51f49785460..b0402726367e6 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611c.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611c.c @@ -622,6 +622,7 @@ static void lt9611c_bridge_atomic_pre_enable(struct drm_bridge *bridge, ret = regulator_bulk_enable(ARRAY_SIZE(lt9611c->supplies), lt9611c->supplies); if (ret) dev_err(lt9611c->dev, "regulator bulk enable failed.\n"); + lt9611c_reset(lt9611c); } static void lt9611c_bridge_atomic_enable(struct drm_bridge *bridge, @@ -776,17 +777,6 @@ static int lt9611c_hdmi_clear_avi_infoframe(struct drm_bridge *bridge) return 0; } -static int lt9611c_hdmi_write_hdmi_infoframe(struct drm_bridge *bridge, - const u8 *buffer, size_t len) -{ - return 0; -} - -static int lt9611c_hdmi_clear_hdmi_infoframe(struct drm_bridge *bridge) -{ - return 0; -} - static int lt9611c_hdmi_write_audio_infoframe(struct drm_bridge *bridge, const u8 *buffer, size_t len) { @@ -905,8 +895,6 @@ static const struct drm_bridge_funcs lt9611c_bridge_funcs = { .hdmi_tmds_char_rate_valid = lt9611c_hdmi_tmds_char_rate_valid, .hdmi_write_avi_infoframe = lt9611c_hdmi_write_avi_infoframe, .hdmi_clear_avi_infoframe = lt9611c_hdmi_clear_avi_infoframe, - .hdmi_write_hdmi_infoframe = lt9611c_hdmi_write_hdmi_infoframe, - .hdmi_clear_hdmi_infoframe = lt9611c_hdmi_clear_hdmi_infoframe, .hdmi_write_audio_infoframe = lt9611c_hdmi_write_audio_infoframe, .hdmi_clear_audio_infoframe = lt9611c_hdmi_clear_audio_infoframe, @@ -1037,13 +1025,6 @@ static int lt9611c_probe(struct i2c_client *client) lt9611c->dev = dev; lt9611c->client = client; lt9611c->chip_type = id->driver_data; - - if (dev->of_node) { - lt9611c->chip_type = (uintptr_t)of_device_get_match_data(dev); - } else { - lt9611c->chip_type = id->driver_data; - } - ret = devm_mutex_init(dev, <9611c->ocm_lock); if (ret) return dev_err_probe(dev, ret, "failed to init mutex\n"); @@ -1130,9 +1111,6 @@ static int lt9611c_probe(struct i2c_client *client) DRM_BRIDGE_OP_HDMI_AUDIO; lt9611c->bridge.type = DRM_MODE_CONNECTOR_HDMIA; - lt9611c->bridge.vendor = "Lontium"; - lt9611c->bridge.product = "LT9611C"; - lt9611c->bridge.hdmi_audio_dev = dev; lt9611c->bridge.hdmi_audio_max_i2s_playback_channels = 8; lt9611c->bridge.hdmi_audio_dai_port = 2; @@ -1158,6 +1136,7 @@ static int lt9611c_probe(struct i2c_client *client) lt9611c->hdmi_connected = false; i2c_set_clientdata(client, lt9611c); enable_irq(client->irq); + lt9611c_reset(lt9611c); return 0; @@ -1235,9 +1214,9 @@ static struct i2c_device_id lt9611c_id[] = { }; static const struct of_device_id lt9611c_match_table[] = { - { .compatible = "lontium,lt9611c", .data = (void *)CHIP_LT9611C }, - { .compatible = "lontium,lt9611ex", .data = (void *)CHIP_LT9611EX }, - { .compatible = "lontium,lt9611uxd", .data = (void *)CHIP_LT9611UXD }, + { .compatible = "lontium,lt9611c" }, + { .compatible = "lontium,lt9611ex" }, + { .compatible = "lontium,lt9611uxd" }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, lt9611c_match_table); From 5a41d54e7c081a89de530c5b365b5d527d96b461 Mon Sep 17 00:00:00 2001 From: Salendarsingh Gaud Date: Mon, 13 Jul 2026 21:05:57 +0530 Subject: [PATCH 09/14] Revert "FROMLIST: drm/bridge: lontium-lt9611c: Increase MCU poll timeout to 200ms" Commit is NAKed in upstream, so reverting for now. This reverts commit 316abfa97df77fccd18f51ced1967bb770d39d98. Signed-off-by: Salendarsingh Gaud --- drivers/gpu/drm/bridge/lontium-lt9611c.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/bridge/lontium-lt9611c.c b/drivers/gpu/drm/bridge/lontium-lt9611c.c index b0402726367e6..cb584855fd8f0 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611c.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611c.c @@ -97,7 +97,7 @@ static int lt9611c_read_write_flow(struct lt9611c *lt9611c, u8 *params, regmap_write(lt9611c->regmap, 0xe0de, 0x01); ret = regmap_read_poll_timeout(lt9611c->regmap, 0xe0ae, temp, - temp == 0x01, 1000, 200 * 1000); + temp == 0x01, 1000, 100 * 1000); if (ret) return -ETIMEDOUT; @@ -107,7 +107,7 @@ static int lt9611c_read_write_flow(struct lt9611c *lt9611c, u8 *params, regmap_write(lt9611c->regmap, 0xe0de, 0x02); ret = regmap_read_poll_timeout(lt9611c->regmap, 0xe0ae, temp, - temp == 0x02, 1000, 200 * 1000); + temp == 0x02, 1000, 100 * 1000); if (ret) return -ETIMEDOUT; From 3641d9dddb565860a5fe884dda76e4e0b718896c Mon Sep 17 00:00:00 2001 From: Salendarsingh Gaud Date: Mon, 13 Jul 2026 21:05:57 +0530 Subject: [PATCH 10/14] Revert "FROMLIST: dt-bindings: brige: lt9611c: add port-select property for LT9611C" Commit is NAKed in upstream, so reverting for now. This reverts commit 7aa4c190ba9e3e5521293bc4bac559a5edc92bcd. Signed-off-by: Salendarsingh Gaud --- .../bindings/display/bridge/lontium,lt9611.yaml | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/Documentation/devicetree/bindings/display/bridge/lontium,lt9611.yaml b/Documentation/devicetree/bindings/display/bridge/lontium,lt9611.yaml index 439eae2dd63ea..21c289cf365b5 100644 --- a/Documentation/devicetree/bindings/display/bridge/lontium,lt9611.yaml +++ b/Documentation/devicetree/bindings/display/bridge/lontium,lt9611.yaml @@ -41,17 +41,6 @@ properties: vcc-supply: description: Regulator for 3.3V IO power. - lontium,port-select: - $ref: /schemas/types.yaml#/definitions/uint32 - enum: [0, 1, 2] - default: 0 - description: | - Selects which DSI input port(s) the bridge uses. Only relevant for - the lontium,lt9611c compatible. - 0 = PORT_SELECT_A - single DSI port A (default) - 1 = PORT_SELECT_B - single DSI port B - 2 = PORT_SELECT_AB - dual DSI ports A and B - ports: $ref: /schemas/graph.yaml#/properties/ports @@ -108,8 +97,6 @@ examples: vdd-supply = <<9611_1v8>; vcc-supply = <<9611_3v3>; - lontium,port-select = <1>; - ports { #address-cells = <1>; #size-cells = <0>; From 9e528e0994e3e25a9db88ba617c818e41bbaca16 Mon Sep 17 00:00:00 2001 From: Salendarsingh Gaud Date: Mon, 13 Jul 2026 21:05:57 +0530 Subject: [PATCH 11/14] Revert "FROMLIST: drm/bridge: Add Lontium LT9611C(EX/UXD) MIPI DSI to HDMI driver" Commit is NAKed in upstream, so reverting for now. This reverts commit 3b7c779e74b0af9c4f846e5242c258af657ba1d3. Signed-off-by: Salendarsingh Gaud --- drivers/gpu/drm/bridge/Kconfig | 18 - drivers/gpu/drm/bridge/Makefile | 1 - drivers/gpu/drm/bridge/lontium-lt9611c.c | 1241 ---------------------- 3 files changed, 1260 deletions(-) delete mode 100644 drivers/gpu/drm/bridge/lontium-lt9611c.c diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index b478d9e368bdf..7fef383ed7cb7 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -170,24 +170,6 @@ config DRM_LONTIUM_LT9611 HDMI signals Please say Y if you have such hardware. -config DRM_LONTIUM_LT9611C - tristate "Lontium LT9611C DSI/HDMI bridge" - select SND_SOC_HDMI_CODEC if SND_SOC - depends on OF - select CRC8 - select FW_LOADER - select DRM_PANEL_BRIDGE - select DRM_KMS_HELPER - select DRM_MIPI_DSI - select DRM_DISPLAY_HELPER - select DRM_DISPLAY_HDMI_STATE_HELPER - select REGMAP_I2C - help - Driver for Lontium DSI to HDMI bridge - chip driver that converts dual DSI and I2S to - HDMI signals - Please say Y if you have such hardware. - config DRM_LONTIUM_LT9611UXC tristate "Lontium LT9611UXC DSI/HDMI bridge" select SND_SOC_HDMI_CODEC if SND_SOC diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index 0fb5df8c4fd5a..07eeb13fa4978 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile @@ -15,7 +15,6 @@ obj-$(CONFIG_DRM_ITE_IT6505) += ite-it6505.o obj-$(CONFIG_DRM_LONTIUM_LT8912B) += lontium-lt8912b.o obj-$(CONFIG_DRM_LONTIUM_LT9211) += lontium-lt9211.o obj-$(CONFIG_DRM_LONTIUM_LT9611) += lontium-lt9611.o -obj-$(CONFIG_DRM_LONTIUM_LT9611C) += lontium-lt9611c.o obj-$(CONFIG_DRM_LONTIUM_LT9611UXC) += lontium-lt9611uxc.o obj-$(CONFIG_DRM_LONTIUM_LT8713SX) += lontium-lt8713sx.o obj-$(CONFIG_DRM_LVDS_CODEC) += lvds-codec.o diff --git a/drivers/gpu/drm/bridge/lontium-lt9611c.c b/drivers/gpu/drm/bridge/lontium-lt9611c.c deleted file mode 100644 index cb584855fd8f0..0000000000000 --- a/drivers/gpu/drm/bridge/lontium-lt9611c.c +++ /dev/null @@ -1,1241 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2026 Lontium Semiconductor, Inc. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define FW_SIZE (64 * 1024) -#define LT_PAGE_SIZE 256 -#define FW_FILE "Lontium/lt9611c_fw.bin" -#define LT9611C_CRC_POLYNOMIAL 0x31 -#define LT9611C_PAGE_CONTROL 0xff - -enum lt9611_chip_type { - CHIP_LT9611C = 0, - CHIP_LT9611EX, - CHIP_LT9611UXD, -}; - -struct lt9611c { - struct device *dev; - struct i2c_client *client; - struct drm_bridge bridge; - struct regmap *regmap; - /* Protects all accesses to registers by stopping the on-chip MCU */ - struct mutex ocm_lock; - struct work_struct work; - struct device_node *dsi0_node; - struct device_node *dsi1_node; - struct mipi_dsi_device *dsi0; - struct mipi_dsi_device *dsi1; - struct gpio_desc *reset_gpio; - struct regulator_bulk_data supplies[2]; - int fw_version; - /* Chip variant: C/EX/UXD */ - enum lt9611_chip_type chip_type; - /* HDMI cable connection status */ - bool hdmi_connected; -}; - -DECLARE_CRC8_TABLE(lt9611c_crc8_table); - -static const struct regmap_range_cfg lt9611c_ranges[] = { - { - .name = "register_range", - .range_min = 0, - .range_max = 0xfe9c, - .selector_reg = LT9611C_PAGE_CONTROL, - .selector_mask = 0xff, - .selector_shift = 0, - .window_start = 0, - .window_len = 0x100, - }, -}; - -static const struct regmap_config lt9611c_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - .max_register = 0xfe9c, - .ranges = lt9611c_ranges, - .num_ranges = ARRAY_SIZE(lt9611c_ranges), -}; - -static int lt9611c_read_write_flow(struct lt9611c *lt9611c, u8 *params, - unsigned int param_count, u8 *return_buffer, - unsigned int return_count) -{ - int ret; - unsigned int i; - unsigned int temp; - unsigned int max_params = 0xe0dd - 0xe0b0 + 1; - - regmap_write(lt9611c->regmap, 0xe0de, 0x01); - - ret = regmap_read_poll_timeout(lt9611c->regmap, 0xe0ae, temp, - temp == 0x01, 1000, 100 * 1000); - if (ret) - return -ETIMEDOUT; - - for (i = 0; i < param_count && i < max_params; i++) - regmap_write(lt9611c->regmap, 0xe0b0 + i, params[i]); - - regmap_write(lt9611c->regmap, 0xe0de, 0x02); - - ret = regmap_read_poll_timeout(lt9611c->regmap, 0xe0ae, temp, - temp == 0x02, 1000, 100 * 1000); - if (ret) - return -ETIMEDOUT; - - return regmap_bulk_read(lt9611c->regmap, 0xe085, return_buffer, - return_count); -} - -static void lt9611c_config_parameters(struct lt9611c *lt9611c) -{ - const struct reg_sequence seq_write_paras[] = { - REG_SEQ0(0xe0ee, 0x01), - REG_SEQ0(0xe103, 0x3f), /*fifo rst*/ - REG_SEQ0(0xe103, 0xff), - REG_SEQ0(0xe05e, 0xc1), - REG_SEQ0(0xe058, 0x00), - REG_SEQ0(0xe059, 0x50), - REG_SEQ0(0xe05a, 0x10), - REG_SEQ0(0xe05a, 0x00), - REG_SEQ0(0xe058, 0x21), - }; - - regmap_multi_reg_write(lt9611c->regmap, seq_write_paras, ARRAY_SIZE(seq_write_paras)); -} - -static void lt9611c_wren(struct lt9611c *lt9611c) -{ - regmap_write(lt9611c->regmap, 0xe05a, 0x04); - regmap_write(lt9611c->regmap, 0xe05a, 0x00); -} - -static void lt9611c_wrdi(struct lt9611c *lt9611c) -{ - regmap_write(lt9611c->regmap, 0xe05a, 0x08); - regmap_write(lt9611c->regmap, 0xe05a, 0x00); -} - -static void lt9611c_erase_op(struct lt9611c *lt9611c, u32 addr) -{ - const struct reg_sequence seq_write[] = { - REG_SEQ0(0xe0ee, 0x01), - REG_SEQ0(0xe05a, 0x04), - REG_SEQ0(0xe05a, 0x00), - REG_SEQ0(0xe05b, (addr >> 16) & 0xff), - REG_SEQ0(0xe05c, (addr >> 8) & 0xff), - REG_SEQ0(0xe05d, addr & 0xff), - REG_SEQ0(0xe05a, 0x01), - REG_SEQ0(0xe05a, 0x00), - }; - - regmap_multi_reg_write(lt9611c->regmap, seq_write, ARRAY_SIZE(seq_write)); -} - -static void read_flash_reg_status(struct lt9611c *lt9611c, unsigned int *status) -{ - const struct reg_sequence seq_write[] = { - REG_SEQ0(0xe103, 0x3f), - REG_SEQ0(0xe103, 0xff), - REG_SEQ0(0xe05e, 0x40), - REG_SEQ0(0xe056, 0x05), - REG_SEQ0(0xe055, 0x25), - REG_SEQ0(0xe055, 0x01), - REG_SEQ0(0xe058, 0x21), - }; - - regmap_multi_reg_write(lt9611c->regmap, seq_write, ARRAY_SIZE(seq_write)); - - regmap_read(lt9611c->regmap, 0xe05f, status); -} - -static void lt9611c_crc_to_sram(struct lt9611c *lt9611c) -{ - const struct reg_sequence seq_write[] = { - REG_SEQ0(0xe051, 0x00), - REG_SEQ0(0xe055, 0xc0), - REG_SEQ0(0xe055, 0x80), - REG_SEQ0(0xe05e, 0xc0), - REG_SEQ0(0xe058, 0x21), - }; - - regmap_multi_reg_write(lt9611c->regmap, seq_write, ARRAY_SIZE(seq_write)); -} - -static void lt9611c_data_to_sram(struct lt9611c *lt9611c) -{ - const struct reg_sequence seq_write[] = { - REG_SEQ0(0xe051, 0xff), - REG_SEQ0(0xe055, 0x80), - REG_SEQ0(0xe05e, 0xc0), - REG_SEQ0(0xe058, 0x21), - }; - - regmap_multi_reg_write(lt9611c->regmap, seq_write, ARRAY_SIZE(seq_write)); -} - -static void lt9611c_sram_to_flash(struct lt9611c *lt9611c, size_t addr) -{ - const struct reg_sequence seq_write[] = { - REG_SEQ0(0xe05b, (addr >> 16) & 0xff), - REG_SEQ0(0xe05c, (addr >> 8) & 0xff), - REG_SEQ0(0xe05d, addr & 0xff), - REG_SEQ0(0xe05a, 0x30), - REG_SEQ0(0xe05a, 0x00), - }; - - regmap_multi_reg_write(lt9611c->regmap, seq_write, ARRAY_SIZE(seq_write)); -} - -static void lt9611c_block_erase(struct lt9611c *lt9611c) -{ - struct device *dev = lt9611c->dev; - int i; - unsigned int block_num; - unsigned int flash_status = 0; - u32 flash_addr = 0; - - for (block_num = 0; block_num < 2; block_num++) { - flash_addr = (block_num * 0x008000); - lt9611c_erase_op(lt9611c, flash_addr); - msleep(100); - i = 0; - while (1) { - read_flash_reg_status(lt9611c, &flash_status); - if ((flash_status & 0x01) == 0) - break; - - if (i > 50) - break; - - i++; - msleep(50); - } - } - - dev_dbg(dev, "erase flash done.\n"); -} - -static int lt9611c_write_data(struct lt9611c *lt9611c, const struct firmware *fw, size_t addr) -{ - struct device *dev = lt9611c->dev; - int ret; - unsigned int page = 0, num = 0, i = 0; - size_t size, index; - const u8 *data; - u8 value; - - data = fw->data; - size = fw->size; - page = (size + LT_PAGE_SIZE - 1) / LT_PAGE_SIZE; - if (page * LT_PAGE_SIZE > FW_SIZE) { - dev_err(dev, "firmware size out of range\n"); - return -EINVAL; - } - - dev_dbg(dev, "%u pages, total size %zu byte\n", page, size); - - for (num = 0; num < page; num++) { - lt9611c_data_to_sram(lt9611c); - - for (i = 0; i < LT_PAGE_SIZE; i++) { - index = num * LT_PAGE_SIZE + i; - value = (index < size) ? data[index] : 0xff; - - ret = regmap_write(lt9611c->regmap, 0xe059, value); - if (ret < 0) { - dev_err(dev, "write error at page %u, index %u\n", num, i); - return ret; - } - } - - lt9611c_wren(lt9611c); - lt9611c_sram_to_flash(lt9611c, addr); - - addr += LT_PAGE_SIZE; - } - - lt9611c_wrdi(lt9611c); - - return 0; -} - -static int lt9611c_write_crc(struct lt9611c *lt9611c, u8 fw_crc, size_t addr) -{ - struct device *dev = lt9611c->dev; - int ret; - - lt9611c_crc_to_sram(lt9611c); - ret = regmap_write(lt9611c->regmap, 0xe059, fw_crc); - if (ret < 0) { - dev_err(dev, "failed to write crc\n"); - return ret; - } - - lt9611c_wren(lt9611c); - lt9611c_sram_to_flash(lt9611c, addr); - lt9611c_wrdi(lt9611c); - - dev_dbg(dev, "crc 0x%02x written to flash at addr 0x%zx\n", fw_crc, addr); - - return 0; -} - -static void lt9611c_reset(struct lt9611c *lt9611c) -{ - gpiod_set_value_cansleep(lt9611c->reset_gpio, 1); - msleep(20); - - gpiod_set_value_cansleep(lt9611c->reset_gpio, 0); - msleep(20); - - gpiod_set_value_cansleep(lt9611c->reset_gpio, 1); - msleep(400); - - dev_dbg(lt9611c->dev, "lt9611c reset"); -} - -static int lt9611c_upgrade_result(struct lt9611c *lt9611c, u8 fw_crc) -{ - struct device *dev = lt9611c->dev; - unsigned int crc_result; - - regmap_write(lt9611c->regmap, 0xe0ee, 0x01); - regmap_read(lt9611c->regmap, 0xe021, &crc_result); - - if (crc_result != fw_crc) { - dev_err(dev, "lt9611c fw upgrade failed, expected crc=0x%02x, read crc=0x%02x\n", - fw_crc, crc_result); - return -1; - } - - dev_dbg(dev, "lt9611c firmware upgrade success, crc=0x%02x\n", crc_result); - return 0; -} - -static int lt9611c_firmware_upgrade(struct lt9611c *lt9611c) -{ - struct device *dev = lt9611c->dev; - const struct firmware *fw; - u8 *buffer; - size_t total_size = FW_SIZE - 1; - u8 fw_crc; - int ret; - - /* 1. load firmware */ - ret = request_firmware(&fw, FW_FILE, dev); - if (ret) - return dev_err_probe(dev, ret, "failed to load '%s'\n", FW_FILE); - - /* 2. check size */ - if (fw->size > total_size) { - dev_err(dev, "firmware too large (%zu > %zu)\n", fw->size, total_size); - ret = -EINVAL; - goto out_release_fw; - } - dev_dbg(dev, "firmware size: %zu bytes\n", fw->size); - - /* 3. calculate crc8 */ - buffer = kzalloc(total_size, GFP_KERNEL); - if (!buffer) { - ret = -ENOMEM; - goto out_release_fw; - } - - memset(buffer, 0xff, total_size); - memcpy(buffer, fw->data, fw->size); - - fw_crc = crc8(lt9611c_crc8_table, buffer, total_size, 0); - kfree(buffer); - - dev_dbg(dev, "firmware crc: 0x%02x\n", fw_crc); - dev_dbg(dev, "starting firmware upgrade, size: %zu bytes\n", fw->size); - - /* 4. firmware upgrade */ - lt9611c_config_parameters(lt9611c); - lt9611c_block_erase(lt9611c); - - ret = lt9611c_write_data(lt9611c, fw, 0); - if (ret < 0) { - dev_err(dev, "failed to write firmware data\n"); - goto out_release_fw; - } - - ret = lt9611c_write_crc(lt9611c, fw_crc, FW_SIZE - 1); - if (ret < 0) { - dev_err(dev, "failed to write firmware crc\n"); - goto out_release_fw; - } - - /* 5. check upgrade of result */ - lt9611c_reset(lt9611c); - ret = lt9611c_upgrade_result(lt9611c, fw_crc); - -out_release_fw: - release_firmware(fw); - return ret; -} - -static struct lt9611c *bridge_to_lt9611c(struct drm_bridge *bridge) -{ - return container_of(bridge, struct lt9611c, bridge); -} - -/*read only*/ -static const struct lt9611c *bridge_to_lt9611c_const(const struct drm_bridge *bridge) -{ - return container_of(bridge, const struct lt9611c, bridge); -} - -static void lt9611c_lock(struct lt9611c *lt9611c) -{ - mutex_lock(<9611c->ocm_lock); - regmap_write(lt9611c->regmap, 0xe0ee, 0x01); -} - -static void lt9611c_unlock(struct lt9611c *lt9611c) -{ - regmap_write(lt9611c->regmap, 0xe0ee, 0x00); - mutex_unlock(<9611c->ocm_lock); -} - -static irqreturn_t lt9611c_irq_thread_handler(int irq, void *dev_id) -{ - struct lt9611c *lt9611c = dev_id; - struct device *dev = lt9611c->dev; - int ret; - unsigned int irq_status; - u8 cmd[5] = {0x52, 0x48, 0x31, 0x3a, 0x00}; - u8 data[5]; - - guard(mutex)(<9611c->ocm_lock); - - ret = regmap_read(lt9611c->regmap, 0xe084, &irq_status); - if (ret) { - dev_err(dev, "failed to read irq status: %d\n", ret); - return IRQ_HANDLED; - } - - if (!(irq_status & BIT(0))) - return IRQ_HANDLED; - - ret = lt9611c_read_write_flow(lt9611c, cmd, ARRAY_SIZE(cmd), data, ARRAY_SIZE(data)); - if (ret) { - dev_err(dev, "failed to read HPD status\n"); - } else { - lt9611c->hdmi_connected = (data[4] == 0x02); - dev_dbg(dev, "HDMI %s\n", lt9611c->hdmi_connected ? "connected" : "disconnected"); - } - - /*Clear interrupt: hardware requires two writes with delay*/ - regmap_write(lt9611c->regmap, 0xe0df, irq_status & BIT(0)); - usleep_range(10000, 12000); - regmap_write(lt9611c->regmap, 0xe0df, irq_status & (~BIT(0))); - - schedule_work(<9611c->work); - - return IRQ_HANDLED; -} - -static void lt9611c_hpd_work(struct work_struct *work) -{ - struct lt9611c *lt9611c = container_of(work, struct lt9611c, work); - bool connected; - - mutex_lock(<9611c->ocm_lock); - connected = lt9611c->hdmi_connected; - mutex_unlock(<9611c->ocm_lock); - - drm_bridge_hpd_notify(<9611c->bridge, - connected ? connector_status_connected : - connector_status_disconnected); -} - -static int lt9611c_regulator_init(struct lt9611c *lt9611c) -{ - struct device *dev = lt9611c->dev; - int ret; - - lt9611c->supplies[0].supply = "vcc"; - lt9611c->supplies[1].supply = "vdd"; - - ret = devm_regulator_bulk_get(dev, 2, lt9611c->supplies); - - return ret; -} - -static struct mipi_dsi_device *lt9611c_attach_dsi(struct lt9611c *lt9611c, - struct device_node *dsi_node) -{ - const struct mipi_dsi_device_info info = { "lt9611c", 0, NULL }; - struct mipi_dsi_device *dsi; - struct mipi_dsi_host *host; - struct device *dev = lt9611c->dev; - int ret; - - host = of_find_mipi_dsi_host_by_node(dsi_node); - if (!host) - return ERR_PTR(dev_err_probe(dev, -EPROBE_DEFER, "failed to find dsi host\n")); - - dsi = devm_mipi_dsi_device_register_full(dev, host, &info); - if (IS_ERR(dsi)) - return ERR_PTR(dev_err_probe(dev, PTR_ERR(dsi), "failed to create dsi device\n")); - - dsi->lanes = 4; - dsi->format = MIPI_DSI_FMT_RGB888; - dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | - MIPI_DSI_MODE_VIDEO_HSE; - - ret = devm_mipi_dsi_attach(dev, dsi); - if (ret < 0) - return ERR_PTR(dev_err_probe(dev, ret, "failed to attach dsi to host\n")); - - return dsi; -} - -static int lt9611c_bridge_attach(struct drm_bridge *bridge, - struct drm_encoder *encoder, - enum drm_bridge_attach_flags flags) -{ - struct lt9611c *lt9611c = bridge_to_lt9611c(bridge); - - return drm_bridge_attach(encoder, lt9611c->bridge.next_bridge, bridge, flags); -} - -static enum drm_mode_status -lt9611c_hdmi_tmds_char_rate_valid(const struct drm_bridge *bridge, - const struct drm_display_mode *mode, - unsigned long long tmds_rate) -{ - const struct lt9611c *lt9611c = bridge_to_lt9611c_const(bridge); - - if (lt9611c->chip_type == CHIP_LT9611UXD) { - if (tmds_rate > 600000000) - return MODE_CLOCK_HIGH; - - } else { - if (tmds_rate > 340000000) - return MODE_CLOCK_HIGH; - } - - if (tmds_rate < 25000000) - return MODE_CLOCK_LOW; - - return MODE_OK; -} - -static void lt9611c_video_setup(struct lt9611c *lt9611c, - const struct drm_display_mode *mode) -{ - struct device *dev = lt9611c->dev; - int ret; - u32 h_total, hactive, hsync_len, hfront_porch, hback_porch; - u32 v_total, vactive, vsync_len, vfront_porch, vback_porch; - u8 timing_set_cmd[26] = {0x57, 0x4d, 0x33, 0x3a}; - u8 return_param[3]; - u8 framerate; - u8 vic = 0x00; - - guard(mutex)(<9611c->ocm_lock); - h_total = mode->htotal; - hactive = mode->hdisplay; - hsync_len = mode->hsync_end - mode->hsync_start; - hfront_porch = mode->hsync_start - mode->hdisplay; - hback_porch = mode->htotal - mode->hsync_end; - - v_total = mode->vtotal; - vactive = mode->vdisplay; - vsync_len = mode->vsync_end - mode->vsync_start; - vfront_porch = mode->vsync_start - mode->vdisplay; - vback_porch = mode->vtotal - mode->vsync_end; - framerate = drm_mode_vrefresh(mode); - vic = drm_match_cea_mode(mode); - - dev_dbg(dev, "hactive=%d, vactive=%d\n", hactive, vactive); - dev_dbg(dev, "framerate=%d\n", framerate); - dev_dbg(dev, "vic = 0x%02x\n", vic); - - timing_set_cmd[4] = (h_total >> 8) & 0xff; - timing_set_cmd[5] = h_total & 0xff; - timing_set_cmd[6] = (hactive >> 8) & 0xff; - timing_set_cmd[7] = hactive & 0xff; - timing_set_cmd[8] = (hfront_porch >> 8) & 0xff; - timing_set_cmd[9] = hfront_porch & 0xff; - timing_set_cmd[10] = (hsync_len >> 8) & 0xff; - timing_set_cmd[11] = hsync_len & 0xff; - timing_set_cmd[12] = (hback_porch >> 8) & 0xff; - timing_set_cmd[13] = hback_porch & 0xff; - timing_set_cmd[14] = (v_total >> 8) & 0xff; - timing_set_cmd[15] = v_total & 0xff; - timing_set_cmd[16] = (vactive >> 8) & 0xff; - timing_set_cmd[17] = vactive & 0xFF; - timing_set_cmd[18] = (vfront_porch >> 8) & 0xff; - timing_set_cmd[19] = vfront_porch & 0xff; - timing_set_cmd[20] = (vsync_len >> 8) & 0xff; - timing_set_cmd[21] = vsync_len & 0xff; - timing_set_cmd[22] = (vback_porch >> 8) & 0xff; - timing_set_cmd[23] = vback_porch & 0xff; - timing_set_cmd[24] = framerate; - timing_set_cmd[25] = vic; - - ret = lt9611c_read_write_flow(lt9611c, - timing_set_cmd, ARRAY_SIZE(timing_set_cmd), - return_param, ARRAY_SIZE(return_param)); - if (ret) - dev_err(dev, "video set failed\n"); -} - -static void lt9611c_bridge_atomic_pre_enable(struct drm_bridge *bridge, - struct drm_atomic_state *state) -{ - struct lt9611c *lt9611c = bridge_to_lt9611c(bridge); - int ret; - - ret = regulator_bulk_enable(ARRAY_SIZE(lt9611c->supplies), lt9611c->supplies); - if (ret) - dev_err(lt9611c->dev, "regulator bulk enable failed.\n"); - lt9611c_reset(lt9611c); -} - -static void lt9611c_bridge_atomic_enable(struct drm_bridge *bridge, - struct drm_atomic_state *state) -{ - struct lt9611c *lt9611c = bridge_to_lt9611c(bridge); - struct drm_connector *connector; - struct drm_connector_state *conn_state; - struct drm_crtc_state *crtc_state; - struct drm_display_mode *mode; - - connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder); - if (WARN_ON(!connector)) - return; - - conn_state = drm_atomic_get_new_connector_state(state, connector); - if (WARN_ON(!conn_state)) - return; - - crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc); - if (WARN_ON(!crtc_state)) - return; - - mode = &crtc_state->adjusted_mode; - - lt9611c_video_setup(lt9611c, mode); -} - -static void lt9611c_bridge_atomic_post_disable(struct drm_bridge *bridge, - struct drm_atomic_state *state) -{ - struct lt9611c *lt9611c = bridge_to_lt9611c(bridge); - int ret; - - ret = regulator_bulk_disable(ARRAY_SIZE(lt9611c->supplies), lt9611c->supplies); - if (ret) - dev_err(lt9611c->dev, "regulator bulk disable failed.\n"); - gpiod_set_value_cansleep(lt9611c->reset_gpio, 0); -} - -static enum drm_connector_status -lt9611c_bridge_detect(struct drm_bridge *bridge, struct drm_connector *connector) -{ - struct lt9611c *lt9611c = bridge_to_lt9611c(bridge); - struct device *dev = lt9611c->dev; - int ret; - bool connected = false; - u8 cmd[5] = {0x52, 0x48, 0x31, 0x3a, 0x00}; - u8 data[5]; - - guard(mutex)(<9611c->ocm_lock); - - ret = lt9611c_read_write_flow(lt9611c, cmd, ARRAY_SIZE(cmd), data, ARRAY_SIZE(data)); - if (ret) - dev_err(dev, "failed to read HPD status (err=%d)\n", ret); - else - connected = (data[4] == 0x02); - - lt9611c->hdmi_connected = connected; - - return connected ? connector_status_connected : - connector_status_disconnected; -} - -static int lt9611c_get_edid_block(void *data, u8 *buf, - unsigned int block, size_t len) -{ - struct lt9611c *lt9611c = data; - struct device *dev = lt9611c->dev; - u8 cmd[5] = {0x52, 0x48, 0x33, 0x3a, 0x00}; - u8 packet[37]; - int ret, i, offset = 0; - - if (len != 128) - return -EINVAL; - guard(mutex)(<9611c->ocm_lock); - - for (i = 0; i < 4; i++) { - cmd[4] = block * 4 + i; - ret = lt9611c_read_write_flow(lt9611c, cmd, ARRAY_SIZE(cmd), - packet, ARRAY_SIZE(packet)); - if (ret) { - dev_err(dev, "Failed to read EDID block %u packet %d\n", - block, i); - return ret; - } - memcpy(buf + offset, &packet[5], 32); - offset += 32; - } - - return 0; -} - -static const struct drm_edid *lt9611c_bridge_edid_read(struct drm_bridge *bridge, - struct drm_connector *connector) -{ - struct lt9611c *lt9611c = bridge_to_lt9611c(bridge); - - return drm_edid_read_custom(connector, lt9611c_get_edid_block, lt9611c); -} - -static int lt9611c_hdmi_write_avi_infoframe(struct drm_bridge *bridge, - const u8 *buffer, size_t len) -{ - struct lt9611c *lt9611c = bridge_to_lt9611c(bridge); - u8 *cmd; - u8 data[5]; - int ret; - - guard(mutex)(<9611c->ocm_lock); - - cmd = kmalloc(5 + len, GFP_KERNEL); - if (!cmd) - return -ENOMEM; - - cmd[0] = 0x57; - cmd[1] = 0x48; - cmd[2] = 0x35; - cmd[3] = 0x3a; - cmd[4] = 0x01;/*write avi*/ - memcpy(cmd + 5, buffer, len); - - ret = lt9611c_read_write_flow(lt9611c, cmd, 5 + len, - data, ARRAY_SIZE(data)); - kfree(cmd); - - if (ret < 0) { - dev_err(lt9611c->dev, "write avi infoframe failed!\n"); - return ret; - } - - return 0; -} - -static int lt9611c_hdmi_clear_avi_infoframe(struct drm_bridge *bridge) -{ - struct lt9611c *lt9611c = bridge_to_lt9611c(bridge); - u8 cmd[5] = {0x57, 0x48, 0x42, 0x3a, 0x01}; - u8 data[5]; - int ret; - - guard(mutex)(<9611c->ocm_lock); - - ret = lt9611c_read_write_flow(lt9611c, cmd, ARRAY_SIZE(cmd), - data, ARRAY_SIZE(data)); - - if (ret < 0) { - dev_err(lt9611c->dev, "clear avi infoframe failed!\n"); - return ret; - } - - return 0; -} - -static int lt9611c_hdmi_write_audio_infoframe(struct drm_bridge *bridge, - const u8 *buffer, size_t len) -{ - struct lt9611c *lt9611c = bridge_to_lt9611c(bridge); - u8 *cmd; - u8 data[5]; - int ret; - - guard(mutex)(<9611c->ocm_lock); - - cmd = kmalloc(5 + len, GFP_KERNEL); - if (!cmd) - return -ENOMEM; - - cmd[0] = 0x57; - cmd[1] = 0x48; - cmd[2] = 0x35; - cmd[3] = 0x3a; - cmd[4] = 0x02;/*write audio*/ - memcpy(cmd + 5, buffer, len); - - ret = lt9611c_read_write_flow(lt9611c, cmd, 5 + len, - data, ARRAY_SIZE(data)); - - kfree(cmd); - - if (ret < 0) { - dev_err(lt9611c->dev, "write audio infoframe failed!\n"); - return ret; - } - - return 0; -} - -static int lt9611c_hdmi_clear_audio_infoframe(struct drm_bridge *bridge) -{ - struct lt9611c *lt9611c = bridge_to_lt9611c(bridge); - u8 cmd[5] = {0x57, 0x48, 0x42, 0x3a, 0x02}; - u8 data[5]; - int ret; - - guard(mutex)(<9611c->ocm_lock); - - ret = lt9611c_read_write_flow(lt9611c, cmd, ARRAY_SIZE(cmd), - data, ARRAY_SIZE(data)); - - if (ret < 0) { - dev_err(lt9611c->dev, "clear audio infoframe failed!\n"); - return ret; - } - - return 0; -} - -static int lt9611c_hdmi_audio_prepare(struct drm_bridge *bridge, - struct drm_connector *connector, - struct hdmi_codec_daifmt *fmt, - struct hdmi_codec_params *hparms) -{ - struct lt9611c *lt9611c = bridge_to_lt9611c(bridge); - u8 audio_cmd[6] = {0x57, 0x48, 0x36, 0x3a}; - u8 data[5]; - int ret; - - if (hparms->sample_width == 32) - return -EINVAL; - - switch (fmt->fmt) { - case HDMI_I2S: - audio_cmd[4] = 0x01; - break; - case HDMI_SPDIF: - audio_cmd[4] = 0x02; - break; - default: - return -EINVAL; - } - - audio_cmd[5] = hparms->channels; - guard(mutex)(<9611c->ocm_lock); - - ret = lt9611c_read_write_flow(lt9611c, audio_cmd, sizeof(audio_cmd), - data, sizeof(data)); - if (ret < 0) { - dev_err(lt9611c->dev, "set audio info failed!\n"); - return ret; - } - - return drm_atomic_helper_connector_hdmi_update_audio_infoframe(connector, - &hparms->cea); -} - -static void lt9611c_hdmi_audio_shutdown(struct drm_bridge *bridge, - struct drm_connector *connector) -{ - drm_atomic_helper_connector_hdmi_clear_audio_infoframe(connector); -} - -static int lt9611c_hdmi_audio_startup(struct drm_bridge *bridge, - struct drm_connector *connector) -{ - return 0; -} - -static const struct drm_bridge_funcs lt9611c_bridge_funcs = { - .attach = lt9611c_bridge_attach, - .detect = lt9611c_bridge_detect, - .edid_read = lt9611c_bridge_edid_read, - .atomic_pre_enable = lt9611c_bridge_atomic_pre_enable, - .atomic_enable = lt9611c_bridge_atomic_enable, - .atomic_post_disable = lt9611c_bridge_atomic_post_disable, - .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, - .atomic_reset = drm_atomic_helper_bridge_reset, - - .hdmi_tmds_char_rate_valid = lt9611c_hdmi_tmds_char_rate_valid, - .hdmi_write_avi_infoframe = lt9611c_hdmi_write_avi_infoframe, - .hdmi_clear_avi_infoframe = lt9611c_hdmi_clear_avi_infoframe, - .hdmi_write_audio_infoframe = lt9611c_hdmi_write_audio_infoframe, - .hdmi_clear_audio_infoframe = lt9611c_hdmi_clear_audio_infoframe, - - .hdmi_audio_startup = lt9611c_hdmi_audio_startup, - .hdmi_audio_prepare = lt9611c_hdmi_audio_prepare, - .hdmi_audio_shutdown = lt9611c_hdmi_audio_shutdown, -}; - -static int lt9611c_parse_dt(struct device *dev, - struct lt9611c *lt9611c) -{ - lt9611c->dsi0_node = of_graph_get_remote_node(dev->of_node, 0, -1); - if (!lt9611c->dsi0_node) - return dev_err_probe(dev, -ENODEV, "failed to get remote node for primary dsi\n"); - - lt9611c->dsi1_node = of_graph_get_remote_node(dev->of_node, 1, -1); - - return drm_of_find_panel_or_bridge(dev->of_node, 2, -1, NULL, <9611c->bridge.next_bridge); -} - -static int lt9611c_gpio_init(struct lt9611c *lt9611c) -{ - struct device *dev = lt9611c->dev; - - lt9611c->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(lt9611c->reset_gpio)) - return dev_err_probe(dev, PTR_ERR(lt9611c->reset_gpio), - "failed to acquire reset gpio\n"); - - return 0; -} - -static int lt9611c_read_version(struct lt9611c *lt9611c) -{ - u8 buf[2]; - int ret; - - ret = regmap_write(lt9611c->regmap, 0xe0ee, 0x01); - if (ret) - return ret; - - ret = regmap_bulk_read(lt9611c->regmap, 0xe080, buf, ARRAY_SIZE(buf)); - if (ret) - return ret; - - return (buf[0] << 8) | buf[1]; -} - -static int lt9611c_read_chipid(struct lt9611c *lt9611c) -{ - struct device *dev = lt9611c->dev; - u8 chipid[2]; - int ret; - - ret = regmap_write(lt9611c->regmap, 0xe0ee, 0x01); - if (ret) - return ret; - - ret = regmap_bulk_read(lt9611c->regmap, 0xe100, chipid, 2); - if (ret) - return ret; - - if (chipid[0] != 0x23 || chipid[1] != 0x06) { - dev_err(dev, "ChipID: 0x%02x 0x%02x\n", chipid[0], chipid[1]); - return -ENODEV; - } - - return 0; -} - -static ssize_t lt9611c_firmware_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t len) -{ - struct lt9611c *lt9611c = dev_get_drvdata(dev); - int ret; - - lt9611c_lock(lt9611c); - - ret = lt9611c_firmware_upgrade(lt9611c); - if (ret < 0) - dev_err(dev, "upgrade failure\n"); - - lt9611c_unlock(lt9611c); - - return ret < 0 ? ret : len; -} - -static ssize_t lt9611c_firmware_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lt9611c *lt9611c = dev_get_drvdata(dev); - - return sysfs_emit(buf, "0x%04x\n", lt9611c->fw_version); -} - -static DEVICE_ATTR_RW(lt9611c_firmware); - -static struct attribute *lt9611c_attrs[] = { - &dev_attr_lt9611c_firmware.attr, - NULL, -}; - -static const struct attribute_group lt9611c_attr_group = { - .attrs = lt9611c_attrs, -}; - -static const struct attribute_group *lt9611c_attr_groups[] = { - <9611c_attr_group, - NULL, -}; - -static int lt9611c_probe(struct i2c_client *client) -{ - const struct i2c_device_id *id = i2c_client_get_device_id(client); - struct lt9611c *lt9611c; - struct device *dev = &client->dev; - bool fw_updated = false; - int ret; - - crc8_populate_msb(lt9611c_crc8_table, LT9611C_CRC_POLYNOMIAL); - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) - return dev_err_probe(dev, -ENODEV, "device doesn't support I2C\n"); - - lt9611c = devm_drm_bridge_alloc(dev, struct lt9611c, bridge, <9611c_bridge_funcs); - if (IS_ERR(lt9611c)) - return dev_err_probe(dev, PTR_ERR(lt9611c), "drm bridge alloc failed.\n"); - - lt9611c->dev = dev; - lt9611c->client = client; - lt9611c->chip_type = id->driver_data; - ret = devm_mutex_init(dev, <9611c->ocm_lock); - if (ret) - return dev_err_probe(dev, ret, "failed to init mutex\n"); - - lt9611c->regmap = devm_regmap_init_i2c(client, <9611c_regmap_config); - if (IS_ERR(lt9611c->regmap)) - return dev_err_probe(dev, PTR_ERR(lt9611c->regmap), "regmap i2c init failed\n"); - - ret = lt9611c_parse_dt(dev, lt9611c); - if (ret) - return dev_err_probe(dev, ret, "failed to parse device tree\n"); - - ret = lt9611c_gpio_init(lt9611c); - if (ret < 0) - goto err_of_put; - - ret = lt9611c_regulator_init(lt9611c); - if (ret < 0) - goto err_of_put; - - ret = regulator_bulk_enable(ARRAY_SIZE(lt9611c->supplies), lt9611c->supplies); - if (ret) - goto err_of_put; - - lt9611c_reset(lt9611c); - - lt9611c_lock(lt9611c); - - ret = lt9611c_read_chipid(lt9611c); - if (ret < 0) { - dev_err(dev, "failed to read chip id.\n"); - lt9611c_unlock(lt9611c); - goto err_disable_regulators; - } - -retry: - lt9611c->fw_version = lt9611c_read_version(lt9611c); - if (lt9611c->fw_version < 0) { - dev_err(dev, "failed to read fw version\n"); - ret = -EOPNOTSUPP; - lt9611c_unlock(lt9611c); - goto err_disable_regulators; - - } else if (lt9611c->fw_version == 0) { - if (!fw_updated) { - fw_updated = true; - ret = lt9611c_firmware_upgrade(lt9611c); - if (ret < 0) { - lt9611c_unlock(lt9611c); - goto err_disable_regulators; - } - - goto retry; - - } else { - dev_err(dev, "fw version 0x%04x, update failed\n", lt9611c->fw_version); - ret = -EOPNOTSUPP; - lt9611c_unlock(lt9611c); - goto err_disable_regulators; - } - } - - lt9611c_unlock(lt9611c); - dev_dbg(dev, "current version:0x%04x", lt9611c->fw_version); - - INIT_WORK(<9611c->work, lt9611c_hpd_work); - - ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, - lt9611c_irq_thread_handler, - IRQF_TRIGGER_FALLING | - IRQF_ONESHOT | - IRQF_NO_AUTOEN, - "lt9611c", lt9611c); - if (ret) { - dev_err(dev, "failed to request irq\n"); - goto err_disable_regulators; - } - - lt9611c->bridge.of_node = client->dev.of_node; - lt9611c->bridge.ops = DRM_BRIDGE_OP_DETECT | - DRM_BRIDGE_OP_EDID | - DRM_BRIDGE_OP_HPD | - DRM_BRIDGE_OP_HDMI | - DRM_BRIDGE_OP_HDMI_AUDIO; - lt9611c->bridge.type = DRM_MODE_CONNECTOR_HDMIA; - - lt9611c->bridge.hdmi_audio_dev = dev; - lt9611c->bridge.hdmi_audio_max_i2s_playback_channels = 8; - lt9611c->bridge.hdmi_audio_dai_port = 2; - - devm_drm_bridge_add(dev, <9611c->bridge); - - /* Attach primary DSI */ - lt9611c->dsi0 = lt9611c_attach_dsi(lt9611c, lt9611c->dsi0_node); - if (IS_ERR(lt9611c->dsi0)) { - ret = PTR_ERR(lt9611c->dsi0); - goto err_remove_bridge; - } - - /* Attach secondary DSI, if specified */ - if (lt9611c->dsi1_node) { - lt9611c->dsi1 = lt9611c_attach_dsi(lt9611c, lt9611c->dsi1_node); - if (IS_ERR(lt9611c->dsi1)) { - ret = PTR_ERR(lt9611c->dsi1); - goto err_remove_bridge; - } - } - - lt9611c->hdmi_connected = false; - i2c_set_clientdata(client, lt9611c); - enable_irq(client->irq); - lt9611c_reset(lt9611c); - - return 0; - -err_remove_bridge: - free_irq(client->irq, lt9611c); - cancel_work_sync(<9611c->work); - drm_bridge_remove(<9611c->bridge); - -err_disable_regulators: - regulator_bulk_disable(ARRAY_SIZE(lt9611c->supplies), lt9611c->supplies); - -err_of_put: - of_node_put(lt9611c->dsi1_node); - of_node_put(lt9611c->dsi0_node); - - return ret; -} - -static void lt9611c_remove(struct i2c_client *client) -{ - struct lt9611c *lt9611c = i2c_get_clientdata(client); - - free_irq(client->irq, lt9611c); - cancel_work_sync(<9611c->work); - regulator_bulk_disable(ARRAY_SIZE(lt9611c->supplies), lt9611c->supplies); - of_node_put(lt9611c->dsi1_node); - of_node_put(lt9611c->dsi0_node); -} - -static int lt9611c_bridge_suspend(struct device *dev) -{ - struct lt9611c *lt9611c = dev_get_drvdata(dev); - int ret; - - dev_dbg(lt9611c->dev, "suspend\n"); - disable_irq(lt9611c->client->irq); - ret = regulator_bulk_disable(ARRAY_SIZE(lt9611c->supplies), lt9611c->supplies); - if (ret) { - dev_err(lt9611c->dev, "regulator bulk disable failed.\n"); - return ret; - } - gpiod_set_value_cansleep(lt9611c->reset_gpio, 0); - - return ret; -} - -static int lt9611c_bridge_resume(struct device *dev) -{ - struct lt9611c *lt9611c = dev_get_drvdata(dev); - int ret; - - ret = regulator_bulk_enable(ARRAY_SIZE(lt9611c->supplies), lt9611c->supplies); - if (ret) { - dev_err(lt9611c->dev, "regulator bulk enable failed.\n"); - return ret; - } - enable_irq(lt9611c->client->irq); - lt9611c_reset(lt9611c); - dev_dbg(lt9611c->dev, "resume\n"); - - return ret; -} - -static const struct dev_pm_ops lt9611c_bridge_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(lt9611c_bridge_suspend, - lt9611c_bridge_resume) -}; - -static struct i2c_device_id lt9611c_id[] = { - /* chip_type */ - { "lontium,lt9611c", 0 }, - { "lontium,lt9611ex", 1 }, - { "lontium,lt9611uxd", 2 }, - { /* sentinel */ } -}; - -static const struct of_device_id lt9611c_match_table[] = { - { .compatible = "lontium,lt9611c" }, - { .compatible = "lontium,lt9611ex" }, - { .compatible = "lontium,lt9611uxd" }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, lt9611c_match_table); - -static struct i2c_driver lt9611c_driver = { - .driver = { - .name = "lt9611c", - .of_match_table = lt9611c_match_table, - .pm = <9611c_bridge_pm_ops, - .dev_groups = lt9611c_attr_groups, - }, - .probe = lt9611c_probe, - .remove = lt9611c_remove, - .id_table = lt9611c_id, -}; -module_i2c_driver(lt9611c_driver); - -MODULE_AUTHOR("SunYun Yang "); -MODULE_DESCRIPTION("Lontium LT9611C(EX/UXD) MIPI DSI to HDMI driver"); -MODULE_LICENSE("GPL"); -MODULE_FIRMWARE(FW_FILE); - From 4145118e73a6d796b0fafd5adc650340c7c9b675 Mon Sep 17 00:00:00 2001 From: Salendarsingh Gaud Date: Mon, 13 Jul 2026 21:05:57 +0530 Subject: [PATCH 12/14] Revert "FROMLIST: dt-bindings: bridge: Add Lontium LT9611C(EX/UXD) MIPI DSI to HDMI driver" Commit is NAKed in upstream, so reverting for now. This reverts commit 27f88bf2d53e331d7c0d8f6fe8f8256e63d70b0f. Signed-off-by: Salendarsingh Gaud --- .../bindings/display/bridge/lontium,lt9611.yaml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/display/bridge/lontium,lt9611.yaml b/Documentation/devicetree/bindings/display/bridge/lontium,lt9611.yaml index 21c289cf365b5..655db8cfdc25f 100644 --- a/Documentation/devicetree/bindings/display/bridge/lontium,lt9611.yaml +++ b/Documentation/devicetree/bindings/display/bridge/lontium,lt9611.yaml @@ -4,23 +4,19 @@ $id: http://devicetree.org/schemas/display/bridge/lontium,lt9611.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Lontium LT9611(UXC/C/EX/UXD) 2 Port MIPI DSI to HDMI Bridge +title: Lontium LT9611(UXC) 2 Port MIPI to HDMI Bridge maintainers: - Vinod Koul description: | - The LT9611、LT9611UXC、LT9611C、LT9611EX and LT9611UXD - are bridge devices which convert DSI to HDMI + The LT9611 and LT9611UXC are bridge devices which convert DSI to HDMI properties: compatible: enum: - lontium,lt9611 - - lontium,lt9611c - - lontium,lt9611ex - lontium,lt9611uxc - - lontium,lt9611uxd reg: maxItems: 1 From 6b8493e9cea2cfcf39b42e5f162fdb238dd040c3 Mon Sep 17 00:00:00 2001 From: Salendarsingh Gaud Date: Mon, 13 Jul 2026 21:14:23 +0530 Subject: [PATCH 13/14] Revert "BACKPORT: drm/bridge: refactor HDMI InfoFrame callbacks" Reverting as the dependency change is NAKed. This reverts commit 994dee7d453c8a4cc0410add99f622305031cd37. Signed-off-by: Salendarsingh Gaud --- drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 180 +++++++--------- drivers/gpu/drm/bridge/ite-it6263.c | 95 +++++---- drivers/gpu/drm/bridge/lontium-lt9611.c | 143 ++++++------- drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 110 ++++------ .../gpu/drm/display/drm_bridge_connector.c | 70 +------ drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 195 +++++++++--------- drivers/gpu/drm/rockchip/rk3066_hdmi.c | 47 ++--- include/drm/drm_bridge.h | 127 ++---------- 8 files changed, 349 insertions(+), 618 deletions(-) diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index 1050bb62280bb..b9be865413075 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c @@ -887,111 +887,88 @@ static const struct drm_edid *adv7511_bridge_edid_read(struct drm_bridge *bridge return adv7511_edid_read(adv, connector); } -static int adv7511_bridge_hdmi_clear_audio_infoframe(struct drm_bridge *bridge) +static int adv7511_bridge_hdmi_clear_infoframe(struct drm_bridge *bridge, + enum hdmi_infoframe_type type) { struct adv7511 *adv7511 = bridge_to_adv7511(bridge); - adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_AUDIO_INFOFRAME); - - return 0; -} - -static int adv7511_bridge_hdmi_clear_avi_infoframe(struct drm_bridge *bridge) -{ - struct adv7511 *adv7511 = bridge_to_adv7511(bridge); - - adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_AVI_INFOFRAME); - - return 0; -} - -static int adv7511_bridge_hdmi_clear_spd_infoframe(struct drm_bridge *bridge) -{ - struct adv7511 *adv7511 = bridge_to_adv7511(bridge); - - adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_SPD); - - return 0; -} - -static int adv7511_bridge_hdmi_clear_hdmi_infoframe(struct drm_bridge *bridge) -{ - struct adv7511 *adv7511 = bridge_to_adv7511(bridge); - - adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_SPARE1); - - return 0; -} - -static int adv7511_bridge_hdmi_write_audio_infoframe(struct drm_bridge *bridge, - const u8 *buffer, size_t len) -{ - struct adv7511 *adv7511 = bridge_to_adv7511(bridge); - - /* send current Audio infoframe values while updating */ - regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE, - BIT(5), BIT(5)); - - /* The Audio infoframe id is not configurable */ - regmap_bulk_write(adv7511->regmap, ADV7511_REG_AUDIO_INFOFRAME_VERSION, - buffer + 1, len - 1); - - /* use Audio infoframe updated info */ - regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE, - BIT(5), 0); - - adv7511_packet_enable(adv7511, ADV7511_PACKET_ENABLE_AUDIO_INFOFRAME); - - return 0; -} - -static int adv7511_bridge_hdmi_write_avi_infoframe(struct drm_bridge *bridge, - const u8 *buffer, size_t len) -{ - struct adv7511 *adv7511 = bridge_to_adv7511(bridge); - - /* send current AVI infoframe values while updating */ - regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE, - BIT(6), BIT(6)); - - /* The AVI infoframe id is not configurable */ - regmap_bulk_write(adv7511->regmap, ADV7511_REG_AVI_INFOFRAME_VERSION, - buffer + 1, len - 1); - - regmap_write(adv7511->regmap, ADV7511_REG_AUDIO_INFOFRAME_LENGTH, 0x2); - regmap_write(adv7511->regmap, ADV7511_REG_AUDIO_INFOFRAME(1), 0x1); - - /* use AVI infoframe updated info */ - regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE, - BIT(6), 0); - - adv7511_packet_enable(adv7511, ADV7511_PACKET_ENABLE_AVI_INFOFRAME); - - return 0; -} - -static int adv7511_bridge_hdmi_write_spd_infoframe(struct drm_bridge *bridge, - const u8 *buffer, size_t len) -{ - struct adv7511 *adv7511 = bridge_to_adv7511(bridge); - - adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_SPD); - regmap_bulk_write(adv7511->regmap_packet, ADV7511_PACKET_SPD(0), - buffer, len); - adv7511_packet_enable(adv7511, ADV7511_PACKET_ENABLE_SPD); + switch (type) { + case HDMI_INFOFRAME_TYPE_AUDIO: + adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_AUDIO_INFOFRAME); + break; + case HDMI_INFOFRAME_TYPE_AVI: + adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_AVI_INFOFRAME); + break; + case HDMI_INFOFRAME_TYPE_SPD: + adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_SPD); + break; + case HDMI_INFOFRAME_TYPE_VENDOR: + adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_SPARE1); + break; + default: + drm_dbg_driver(adv7511->bridge.dev, "Unsupported HDMI InfoFrame %x\n", type); + break; + } return 0; } -static int adv7511_bridge_hdmi_write_hdmi_infoframe(struct drm_bridge *bridge, - const u8 *buffer, size_t len) +static int adv7511_bridge_hdmi_write_infoframe(struct drm_bridge *bridge, + enum hdmi_infoframe_type type, + const u8 *buffer, size_t len) { struct adv7511 *adv7511 = bridge_to_adv7511(bridge); - adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_SPARE1); - regmap_bulk_write(adv7511->regmap_packet, ADV7511_PACKET_SPARE1(0), - buffer, len); - adv7511_packet_enable(adv7511, ADV7511_PACKET_ENABLE_SPARE1); + switch (type) { + case HDMI_INFOFRAME_TYPE_AUDIO: + /* send current Audio infoframe values while updating */ + regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE, + BIT(5), BIT(5)); + + /* The Audio infoframe id is not configurable */ + regmap_bulk_write(adv7511->regmap, ADV7511_REG_AUDIO_INFOFRAME_VERSION, + buffer + 1, len - 1); + + /* use Audio infoframe updated info */ + regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE, + BIT(5), 0); + + adv7511_packet_enable(adv7511, ADV7511_PACKET_ENABLE_AUDIO_INFOFRAME); + break; + case HDMI_INFOFRAME_TYPE_AVI: + /* send current AVI infoframe values while updating */ + regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE, + BIT(6), BIT(6)); + + /* The AVI infoframe id is not configurable */ + regmap_bulk_write(adv7511->regmap, ADV7511_REG_AVI_INFOFRAME_VERSION, + buffer + 1, len - 1); + + regmap_write(adv7511->regmap, ADV7511_REG_AUDIO_INFOFRAME_LENGTH, 0x2); + regmap_write(adv7511->regmap, ADV7511_REG_AUDIO_INFOFRAME(1), 0x1); + + /* use AVI infoframe updated info */ + regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE, + BIT(6), 0); + + adv7511_packet_enable(adv7511, ADV7511_PACKET_ENABLE_AVI_INFOFRAME); + break; + case HDMI_INFOFRAME_TYPE_SPD: + adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_SPD); + regmap_bulk_write(adv7511->regmap_packet, ADV7511_PACKET_SPD(0), + buffer, len); + adv7511_packet_enable(adv7511, ADV7511_PACKET_ENABLE_SPD); + break; + case HDMI_INFOFRAME_TYPE_VENDOR: + adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_SPARE1); + regmap_bulk_write(adv7511->regmap_packet, ADV7511_PACKET_SPARE1(0), + buffer, len); + adv7511_packet_enable(adv7511, ADV7511_PACKET_ENABLE_SPARE1); + break; + default: + drm_dbg_driver(adv7511->bridge.dev, "Unsupported HDMI InfoFrame %x\n", type); + break; + } return 0; } @@ -1009,14 +986,8 @@ static const struct drm_bridge_funcs adv7511_bridge_funcs = { .atomic_reset = drm_atomic_helper_bridge_reset, .hdmi_tmds_char_rate_valid = adv7511_bridge_hdmi_tmds_char_rate_valid, - .hdmi_clear_audio_infoframe = adv7511_bridge_hdmi_clear_audio_infoframe, - .hdmi_write_audio_infoframe = adv7511_bridge_hdmi_write_audio_infoframe, - .hdmi_clear_avi_infoframe = adv7511_bridge_hdmi_clear_avi_infoframe, - .hdmi_write_avi_infoframe = adv7511_bridge_hdmi_write_avi_infoframe, - .hdmi_clear_spd_infoframe = adv7511_bridge_hdmi_clear_spd_infoframe, - .hdmi_write_spd_infoframe = adv7511_bridge_hdmi_write_spd_infoframe, - .hdmi_clear_hdmi_infoframe = adv7511_bridge_hdmi_clear_hdmi_infoframe, - .hdmi_write_hdmi_infoframe = adv7511_bridge_hdmi_write_hdmi_infoframe, + .hdmi_clear_infoframe = adv7511_bridge_hdmi_clear_infoframe, + .hdmi_write_infoframe = adv7511_bridge_hdmi_write_infoframe, .hdmi_audio_startup = adv7511_hdmi_audio_startup, .hdmi_audio_prepare = adv7511_hdmi_audio_prepare, @@ -1351,8 +1322,7 @@ static int adv7511_probe(struct i2c_client *i2c) adv7511->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID | - DRM_BRIDGE_OP_HDMI | - DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME; + DRM_BRIDGE_OP_HDMI; if (adv7511->i2c_main->irq) adv7511->bridge.ops |= DRM_BRIDGE_OP_HPD; diff --git a/drivers/gpu/drm/bridge/ite-it6263.c b/drivers/gpu/drm/bridge/ite-it6263.c index 3991fb76143c9..2eb8fba7016cb 100644 --- a/drivers/gpu/drm/bridge/ite-it6263.c +++ b/drivers/gpu/drm/bridge/ite-it6263.c @@ -759,62 +759,61 @@ it6263_hdmi_tmds_char_rate_valid(const struct drm_bridge *bridge, return MODE_OK; } -static int it6263_hdmi_clear_avi_infoframe(struct drm_bridge *bridge) +static int it6263_hdmi_clear_infoframe(struct drm_bridge *bridge, + enum hdmi_infoframe_type type) { struct it6263 *it = bridge_to_it6263(bridge); - regmap_write(it->hdmi_regmap, HDMI_REG_AVI_INFOFRM_CTRL, 0); - - return 0; -} - -static int it6263_hdmi_clear_hdmi_infoframe(struct drm_bridge *bridge) -{ - struct it6263 *it = bridge_to_it6263(bridge); - - regmap_write(it->hdmi_regmap, HDMI_REG_PKT_NULL_CTRL, 0); - - return 0; -} - -static int it6263_hdmi_write_avi_infoframe(struct drm_bridge *bridge, - const u8 *buffer, size_t len) -{ - struct it6263 *it = bridge_to_it6263(bridge); - struct regmap *regmap = it->hdmi_regmap; - - /* write the first AVI infoframe data byte chunk(DB1-DB5) */ - regmap_bulk_write(regmap, HDMI_REG_AVI_DB1, - &buffer[HDMI_INFOFRAME_HEADER_SIZE], - HDMI_AVI_DB_CHUNK1_SIZE); - - /* write the second AVI infoframe data byte chunk(DB6-DB13) */ - regmap_bulk_write(regmap, HDMI_REG_AVI_DB6, - &buffer[HDMI_INFOFRAME_HEADER_SIZE + - HDMI_AVI_DB_CHUNK1_SIZE], - HDMI_AVI_DB_CHUNK2_SIZE); - - /* write checksum */ - regmap_write(regmap, HDMI_REG_AVI_CSUM, buffer[3]); - - regmap_write(regmap, HDMI_REG_AVI_INFOFRM_CTRL, - ENABLE_PKT | REPEAT_PKT); + switch (type) { + case HDMI_INFOFRAME_TYPE_AVI: + regmap_write(it->hdmi_regmap, HDMI_REG_AVI_INFOFRM_CTRL, 0); + break; + case HDMI_INFOFRAME_TYPE_VENDOR: + regmap_write(it->hdmi_regmap, HDMI_REG_PKT_NULL_CTRL, 0); + break; + default: + dev_dbg(it->dev, "unsupported HDMI infoframe 0x%x\n", type); + } return 0; } -static int it6263_hdmi_write_hdmi_infoframe(struct drm_bridge *bridge, - const u8 *buffer, size_t len) +static int it6263_hdmi_write_infoframe(struct drm_bridge *bridge, + enum hdmi_infoframe_type type, + const u8 *buffer, size_t len) { struct it6263 *it = bridge_to_it6263(bridge); struct regmap *regmap = it->hdmi_regmap; - /* write header and payload */ - regmap_bulk_write(regmap, HDMI_REG_PKT_HB(0), buffer, len); - - regmap_write(regmap, HDMI_REG_PKT_NULL_CTRL, - ENABLE_PKT | REPEAT_PKT); - + switch (type) { + case HDMI_INFOFRAME_TYPE_AVI: + /* write the first AVI infoframe data byte chunk(DB1-DB5) */ + regmap_bulk_write(regmap, HDMI_REG_AVI_DB1, + &buffer[HDMI_INFOFRAME_HEADER_SIZE], + HDMI_AVI_DB_CHUNK1_SIZE); + + /* write the second AVI infoframe data byte chunk(DB6-DB13) */ + regmap_bulk_write(regmap, HDMI_REG_AVI_DB6, + &buffer[HDMI_INFOFRAME_HEADER_SIZE + + HDMI_AVI_DB_CHUNK1_SIZE], + HDMI_AVI_DB_CHUNK2_SIZE); + + /* write checksum */ + regmap_write(regmap, HDMI_REG_AVI_CSUM, buffer[3]); + + regmap_write(regmap, HDMI_REG_AVI_INFOFRM_CTRL, + ENABLE_PKT | REPEAT_PKT); + break; + case HDMI_INFOFRAME_TYPE_VENDOR: + /* write header and payload */ + regmap_bulk_write(regmap, HDMI_REG_PKT_HB(0), buffer, len); + + regmap_write(regmap, HDMI_REG_PKT_NULL_CTRL, + ENABLE_PKT | REPEAT_PKT); + break; + default: + dev_dbg(it->dev, "unsupported HDMI infoframe 0x%x\n", type); + } return 0; } @@ -831,10 +830,8 @@ static const struct drm_bridge_funcs it6263_bridge_funcs = { .edid_read = it6263_bridge_edid_read, .atomic_get_input_bus_fmts = it6263_bridge_atomic_get_input_bus_fmts, .hdmi_tmds_char_rate_valid = it6263_hdmi_tmds_char_rate_valid, - .hdmi_clear_avi_infoframe = it6263_hdmi_clear_avi_infoframe, - .hdmi_write_avi_infoframe = it6263_hdmi_write_avi_infoframe, - .hdmi_clear_hdmi_infoframe = it6263_hdmi_clear_hdmi_infoframe, - .hdmi_write_hdmi_infoframe = it6263_hdmi_write_hdmi_infoframe, + .hdmi_clear_infoframe = it6263_hdmi_clear_infoframe, + .hdmi_write_infoframe = it6263_hdmi_write_infoframe, }; static int it6263_probe(struct i2c_client *client) diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c index 0628d8e737abb..a2d032ee47447 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611.c @@ -843,96 +843,84 @@ lt9611_atomic_get_input_bus_fmts(struct drm_bridge *bridge, #define LT9611_INFOFRAME_AUDIO 0x02 #define LT9611_INFOFRAME_AVI 0x08 #define LT9611_INFOFRAME_SPD 0x10 -#define LT9611_INFOFRAME_HDMI 0x20 +#define LT9611_INFOFRAME_VENDOR 0x20 -static int lt9611_hdmi_clear_audio_infoframe(struct drm_bridge *bridge) +static int lt9611_hdmi_clear_infoframe(struct drm_bridge *bridge, + enum hdmi_infoframe_type type) { struct lt9611 *lt9611 = bridge_to_lt9611(bridge); + unsigned int mask; - regmap_update_bits(lt9611->regmap, 0x843d, LT9611_INFOFRAME_AUDIO, 0); - - return 0; -} - -static int lt9611_hdmi_clear_avi_infoframe(struct drm_bridge *bridge) -{ - struct lt9611 *lt9611 = bridge_to_lt9611(bridge); - - regmap_update_bits(lt9611->regmap, 0x843d, LT9611_INFOFRAME_AVI, 0); - - return 0; -} - -static int lt9611_hdmi_clear_spd_infoframe(struct drm_bridge *bridge) -{ - struct lt9611 *lt9611 = bridge_to_lt9611(bridge); - - regmap_update_bits(lt9611->regmap, 0x843d, LT9611_INFOFRAME_SPD, 0); - - return 0; -} - -static int lt9611_hdmi_clear_hdmi_infoframe(struct drm_bridge *bridge) -{ - struct lt9611 *lt9611 = bridge_to_lt9611(bridge); - - regmap_update_bits(lt9611->regmap, 0x843d, LT9611_INFOFRAME_HDMI, 0); - - return 0; -} - -static int lt9611_hdmi_write_audio_infoframe(struct drm_bridge *bridge, - const u8 *buffer, size_t len) -{ - struct lt9611 *lt9611 = bridge_to_lt9611(bridge); - int i; + switch (type) { + case HDMI_INFOFRAME_TYPE_AUDIO: + mask = LT9611_INFOFRAME_AUDIO; + break; - for (i = 0; i < len; i++) - regmap_write(lt9611->regmap, 0x84b2 + i, buffer[i]); + case HDMI_INFOFRAME_TYPE_AVI: + mask = LT9611_INFOFRAME_AVI; + break; - regmap_update_bits(lt9611->regmap, 0x843d, LT9611_INFOFRAME_AUDIO, LT9611_INFOFRAME_AUDIO); + case HDMI_INFOFRAME_TYPE_SPD: + mask = LT9611_INFOFRAME_SPD; + break; - return 0; -} - -static int lt9611_hdmi_write_avi_infoframe(struct drm_bridge *bridge, - const u8 *buffer, size_t len) -{ - struct lt9611 *lt9611 = bridge_to_lt9611(bridge); - int i; + case HDMI_INFOFRAME_TYPE_VENDOR: + mask = LT9611_INFOFRAME_VENDOR; + break; - for (i = 0; i < len; i++) - regmap_write(lt9611->regmap, 0x8440 + i, buffer[i]); + default: + drm_dbg_driver(lt9611->bridge.dev, "Unsupported HDMI InfoFrame %x\n", type); + mask = 0; + break; + } - regmap_update_bits(lt9611->regmap, 0x843d, LT9611_INFOFRAME_AVI, LT9611_INFOFRAME_AVI); + if (mask) + regmap_update_bits(lt9611->regmap, 0x843d, mask, 0); return 0; } -static int lt9611_hdmi_write_spd_infoframe(struct drm_bridge *bridge, - const u8 *buffer, size_t len) +static int lt9611_hdmi_write_infoframe(struct drm_bridge *bridge, + enum hdmi_infoframe_type type, + const u8 *buffer, size_t len) { struct lt9611 *lt9611 = bridge_to_lt9611(bridge); + unsigned int mask, addr; int i; - for (i = 0; i < len; i++) - regmap_write(lt9611->regmap, 0x8493 + i, buffer[i]); - - regmap_update_bits(lt9611->regmap, 0x843d, LT9611_INFOFRAME_SPD, LT9611_INFOFRAME_SPD); - - return 0; -} - -static int lt9611_hdmi_write_hdmi_infoframe(struct drm_bridge *bridge, - const u8 *buffer, size_t len) -{ - struct lt9611 *lt9611 = bridge_to_lt9611(bridge); - int i; + switch (type) { + case HDMI_INFOFRAME_TYPE_AUDIO: + mask = LT9611_INFOFRAME_AUDIO; + addr = 0x84b2; + break; + + case HDMI_INFOFRAME_TYPE_AVI: + mask = LT9611_INFOFRAME_AVI; + addr = 0x8440; + break; + + case HDMI_INFOFRAME_TYPE_SPD: + mask = LT9611_INFOFRAME_SPD; + addr = 0x8493; + break; + + case HDMI_INFOFRAME_TYPE_VENDOR: + mask = LT9611_INFOFRAME_VENDOR; + addr = 0x8474; + break; + + default: + drm_dbg_driver(lt9611->bridge.dev, "Unsupported HDMI InfoFrame %x\n", type); + mask = 0; + break; + } - for (i = 0; i < len; i++) - regmap_write(lt9611->regmap, 0x8474 + i, buffer[i]); + if (mask) { + for (i = 0; i < len; i++) + regmap_write(lt9611->regmap, addr + i, buffer[i]); - regmap_update_bits(lt9611->regmap, 0x843d, LT9611_INFOFRAME_HDMI, LT9611_INFOFRAME_HDMI); + regmap_update_bits(lt9611->regmap, 0x843d, mask, mask); + } return 0; } @@ -1015,14 +1003,8 @@ static const struct drm_bridge_funcs lt9611_bridge_funcs = { .atomic_get_input_bus_fmts = lt9611_atomic_get_input_bus_fmts, .hdmi_tmds_char_rate_valid = lt9611_hdmi_tmds_char_rate_valid, - .hdmi_write_audio_infoframe = lt9611_hdmi_write_audio_infoframe, - .hdmi_clear_audio_infoframe = lt9611_hdmi_clear_audio_infoframe, - .hdmi_write_avi_infoframe = lt9611_hdmi_write_avi_infoframe, - .hdmi_clear_avi_infoframe = lt9611_hdmi_clear_avi_infoframe, - .hdmi_write_spd_infoframe = lt9611_hdmi_write_spd_infoframe, - .hdmi_clear_spd_infoframe = lt9611_hdmi_clear_spd_infoframe, - .hdmi_write_hdmi_infoframe = lt9611_hdmi_write_hdmi_infoframe, - .hdmi_clear_hdmi_infoframe = lt9611_hdmi_clear_hdmi_infoframe, + .hdmi_write_infoframe = lt9611_hdmi_write_infoframe, + .hdmi_clear_infoframe = lt9611_hdmi_clear_infoframe, .hdmi_audio_startup = lt9611_hdmi_audio_startup, .hdmi_audio_prepare = lt9611_hdmi_audio_prepare, @@ -1150,8 +1132,7 @@ static int lt9611_probe(struct i2c_client *client) lt9611->bridge.of_node = client->dev.of_node; lt9611->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_HPD | DRM_BRIDGE_OP_MODES | - DRM_BRIDGE_OP_HDMI | DRM_BRIDGE_OP_HDMI_AUDIO | - DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME; + DRM_BRIDGE_OP_HDMI | DRM_BRIDGE_OP_HDMI_AUDIO; lt9611->bridge.type = DRM_MODE_CONNECTOR_HDMIA; lt9611->bridge.vendor = "Lontium"; lt9611->bridge.product = "LT9611"; diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c index 7331b7a0457e8..d302455875167 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c @@ -25,7 +25,6 @@ #include #include #include -#include #include @@ -914,85 +913,57 @@ dw_hdmi_qp_bridge_tmds_char_rate_valid(const struct drm_bridge *bridge, return MODE_OK; } -static int dw_hdmi_qp_bridge_clear_avi_infoframe(struct drm_bridge *bridge) +static int dw_hdmi_qp_bridge_clear_infoframe(struct drm_bridge *bridge, + enum hdmi_infoframe_type type) { struct dw_hdmi_qp *hdmi = bridge->driver_private; - dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_AVI_TX_EN | PKTSCHED_GCP_TX_EN, - PKTSCHED_PKT_EN); - - return 0; -} - -static int dw_hdmi_qp_bridge_clear_hdmi_infoframe(struct drm_bridge *bridge) -{ - /* FIXME: add support for this InfoFrame */ - - drm_warn_once(bridge->encoder->dev, "HDMI VSI not supported\n"); - - return 0; -} - -static int dw_hdmi_qp_bridge_clear_hdr_drm_infoframe(struct drm_bridge *bridge) -{ - struct dw_hdmi_qp *hdmi = bridge->driver_private; - - dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_DRMI_TX_EN, PKTSCHED_PKT_EN); - - return 0; -} - -static int dw_hdmi_qp_bridge_clear_audio_infoframe(struct drm_bridge *bridge) -{ - struct dw_hdmi_qp *hdmi = bridge->driver_private; - - dw_hdmi_qp_mod(hdmi, 0, - PKTSCHED_ACR_TX_EN | - PKTSCHED_AUDS_TX_EN | - PKTSCHED_AUDI_TX_EN, - PKTSCHED_PKT_EN); - - return 0; -} - -static int dw_hdmi_qp_bridge_write_avi_infoframe(struct drm_bridge *bridge, - const u8 *buffer, size_t len) -{ - struct dw_hdmi_qp *hdmi = bridge->driver_private; - - dw_hdmi_qp_bridge_clear_avi_infoframe(bridge); - - return dw_hdmi_qp_config_avi_infoframe(hdmi, buffer, len); -} + switch (type) { + case HDMI_INFOFRAME_TYPE_AVI: + dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_AVI_TX_EN | PKTSCHED_GCP_TX_EN, + PKTSCHED_PKT_EN); + break; -static int dw_hdmi_qp_bridge_write_hdmi_infoframe(struct drm_bridge *bridge, - const u8 *buffer, size_t len) -{ - dw_hdmi_qp_bridge_clear_hdmi_infoframe(bridge); + case HDMI_INFOFRAME_TYPE_DRM: + dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_DRMI_TX_EN, PKTSCHED_PKT_EN); + break; - /* FIXME: add support for the HDMI VSI */ + case HDMI_INFOFRAME_TYPE_AUDIO: + dw_hdmi_qp_mod(hdmi, 0, + PKTSCHED_ACR_TX_EN | + PKTSCHED_AUDS_TX_EN | + PKTSCHED_AUDI_TX_EN, + PKTSCHED_PKT_EN); + break; + default: + dev_dbg(hdmi->dev, "Unsupported infoframe type %x\n", type); + } return 0; } -static int dw_hdmi_qp_bridge_write_hdr_drm_infoframe(struct drm_bridge *bridge, - const u8 *buffer, size_t len) +static int dw_hdmi_qp_bridge_write_infoframe(struct drm_bridge *bridge, + enum hdmi_infoframe_type type, + const u8 *buffer, size_t len) { struct dw_hdmi_qp *hdmi = bridge->driver_private; - dw_hdmi_qp_bridge_clear_hdr_drm_infoframe(bridge); + dw_hdmi_qp_bridge_clear_infoframe(bridge, type); - return dw_hdmi_qp_config_drm_infoframe(hdmi, buffer, len); -} + switch (type) { + case HDMI_INFOFRAME_TYPE_AVI: + return dw_hdmi_qp_config_avi_infoframe(hdmi, buffer, len); -static int dw_hdmi_qp_bridge_write_audio_infoframe(struct drm_bridge *bridge, - const u8 *buffer, size_t len) -{ - struct dw_hdmi_qp *hdmi = bridge->driver_private; + case HDMI_INFOFRAME_TYPE_DRM: + return dw_hdmi_qp_config_drm_infoframe(hdmi, buffer, len); - dw_hdmi_qp_bridge_clear_audio_infoframe(bridge); + case HDMI_INFOFRAME_TYPE_AUDIO: + return dw_hdmi_qp_config_audio_infoframe(hdmi, buffer, len); - return dw_hdmi_qp_config_audio_infoframe(hdmi, buffer, len); + default: + dev_dbg(hdmi->dev, "Unsupported infoframe type %x\n", type); + return 0; + } } static const struct drm_bridge_funcs dw_hdmi_qp_bridge_funcs = { @@ -1004,14 +975,8 @@ static const struct drm_bridge_funcs dw_hdmi_qp_bridge_funcs = { .detect = dw_hdmi_qp_bridge_detect, .edid_read = dw_hdmi_qp_bridge_edid_read, .hdmi_tmds_char_rate_valid = dw_hdmi_qp_bridge_tmds_char_rate_valid, - .hdmi_clear_avi_infoframe = dw_hdmi_qp_bridge_clear_avi_infoframe, - .hdmi_write_avi_infoframe = dw_hdmi_qp_bridge_write_avi_infoframe, - .hdmi_clear_hdmi_infoframe = dw_hdmi_qp_bridge_clear_hdmi_infoframe, - .hdmi_write_hdmi_infoframe = dw_hdmi_qp_bridge_write_hdmi_infoframe, - .hdmi_clear_hdr_drm_infoframe = dw_hdmi_qp_bridge_clear_hdr_drm_infoframe, - .hdmi_write_hdr_drm_infoframe = dw_hdmi_qp_bridge_write_hdr_drm_infoframe, - .hdmi_clear_audio_infoframe = dw_hdmi_qp_bridge_clear_audio_infoframe, - .hdmi_write_audio_infoframe = dw_hdmi_qp_bridge_write_audio_infoframe, + .hdmi_clear_infoframe = dw_hdmi_qp_bridge_clear_infoframe, + .hdmi_write_infoframe = dw_hdmi_qp_bridge_write_infoframe, .hdmi_audio_startup = dw_hdmi_qp_audio_enable, .hdmi_audio_shutdown = dw_hdmi_qp_audio_disable, .hdmi_audio_prepare = dw_hdmi_qp_audio_prepare, @@ -1116,7 +1081,6 @@ struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev, DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_HDMI | DRM_BRIDGE_OP_HDMI_AUDIO | - DRM_BRIDGE_OP_HDMI_HDR_DRM_INFOFRAME | DRM_BRIDGE_OP_HPD; hdmi->bridge.of_node = pdev->dev.of_node; hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA; diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c index ae02d5ae11ffe..baacd21e7341f 100644 --- a/drivers/gpu/drm/display/drm_bridge_connector.c +++ b/drivers/gpu/drm/display/drm_bridge_connector.c @@ -413,30 +413,7 @@ static int drm_bridge_connector_clear_infoframe(struct drm_connector *connector, if (!bridge) return -EINVAL; - switch (type) { - case HDMI_INFOFRAME_TYPE_AVI: - /* required */ - return bridge->funcs->hdmi_clear_avi_infoframe(bridge); - case HDMI_INFOFRAME_TYPE_VENDOR: - /* required */ - return bridge->funcs->hdmi_clear_hdmi_infoframe(bridge); - case HDMI_INFOFRAME_TYPE_AUDIO: - if (bridge->ops & DRM_BRIDGE_OP_HDMI_AUDIO) - return bridge->funcs->hdmi_clear_audio_infoframe(bridge); - break; - case HDMI_INFOFRAME_TYPE_DRM: - if (bridge->ops & DRM_BRIDGE_OP_HDMI_HDR_DRM_INFOFRAME) - return bridge->funcs->hdmi_clear_hdr_drm_infoframe(bridge); - break; - case HDMI_INFOFRAME_TYPE_SPD: - if (bridge->ops & DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME) - return bridge->funcs->hdmi_clear_spd_infoframe(bridge); - break; - } - - drm_dbg_driver(connector->dev, "Unsupported HDMI InfoFrame %x\n", type); - - return 0; + return bridge->funcs->hdmi_clear_infoframe(bridge, type); } static int drm_bridge_connector_write_infoframe(struct drm_connector *connector, @@ -451,30 +428,7 @@ static int drm_bridge_connector_write_infoframe(struct drm_connector *connector, if (!bridge) return -EINVAL; - switch (type) { - case HDMI_INFOFRAME_TYPE_AVI: - /* required */ - return bridge->funcs->hdmi_write_avi_infoframe(bridge, buffer, len); - case HDMI_INFOFRAME_TYPE_VENDOR: - /* required */ - return bridge->funcs->hdmi_write_hdmi_infoframe(bridge, buffer, len); - case HDMI_INFOFRAME_TYPE_AUDIO: - if (bridge->ops & DRM_BRIDGE_OP_HDMI_AUDIO) - return bridge->funcs->hdmi_write_audio_infoframe(bridge, buffer, len); - break; - case HDMI_INFOFRAME_TYPE_DRM: - if (bridge->ops & DRM_BRIDGE_OP_HDMI_HDR_DRM_INFOFRAME) - return bridge->funcs->hdmi_write_hdr_drm_infoframe(bridge, buffer, len); - break; - case HDMI_INFOFRAME_TYPE_SPD: - if (bridge->ops & DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME) - return bridge->funcs->hdmi_write_spd_infoframe(bridge, buffer, len); - break; - } - - drm_dbg_driver(connector->dev, "Unsupported HDMI InfoFrame %x\n", type); - - return 0; + return bridge->funcs->hdmi_write_infoframe(bridge, type, buffer, len); } static const struct drm_edid * @@ -730,20 +684,8 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm, if (bridge->ops & DRM_BRIDGE_OP_HDMI) { if (bridge_connector->bridge_hdmi) return ERR_PTR(-EBUSY); - if (!bridge->funcs->hdmi_write_avi_infoframe || - !bridge->funcs->hdmi_clear_avi_infoframe || - !bridge->funcs->hdmi_write_hdmi_infoframe || - !bridge->funcs->hdmi_clear_hdmi_infoframe) - return ERR_PTR(-EINVAL); - - if (bridge->ops & DRM_BRIDGE_OP_HDMI_HDR_DRM_INFOFRAME && - (!bridge->funcs->hdmi_write_hdr_drm_infoframe || - !bridge->funcs->hdmi_clear_hdr_drm_infoframe)) - return ERR_PTR(-EINVAL); - - if (bridge->ops & DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME && - (!bridge->funcs->hdmi_write_spd_infoframe || - !bridge->funcs->hdmi_clear_spd_infoframe)) + if (!bridge->funcs->hdmi_write_infoframe || + !bridge->funcs->hdmi_clear_infoframe) return ERR_PTR(-EINVAL); bridge_connector->bridge_hdmi = bridge; @@ -765,9 +707,7 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm, !bridge->hdmi_audio_spdif_playback) return ERR_PTR(-EINVAL); - if (!bridge->funcs->hdmi_write_audio_infoframe || - !bridge->funcs->hdmi_clear_audio_infoframe || - !bridge->funcs->hdmi_audio_prepare || + if (!bridge->funcs->hdmi_audio_prepare || !bridge->funcs->hdmi_audio_shutdown) return ERR_PTR(-EINVAL); diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c index 9b7012692ece9..93a491a103e0a 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c @@ -54,80 +54,9 @@ static void power_off(struct drm_bridge *bridge) #define SPD_IFRAME_LINE_NUMBER 1 #define VENSPEC_IFRAME_LINE_NUMBER 3 -static int msm_hdmi_bridge_clear_avi_infoframe(struct drm_bridge *bridge) +static int msm_hdmi_config_avi_infoframe(struct hdmi *hdmi, + const u8 *buffer, size_t len) { - struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); - struct hdmi *hdmi = hdmi_bridge->hdmi; - u32 val; - - val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0); - val &= ~(HDMI_INFOFRAME_CTRL0_AVI_SEND | - HDMI_INFOFRAME_CTRL0_AVI_CONT); - hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val); - - val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1); - val &= ~HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK; - hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val); - - return 0; -} - -static int msm_hdmi_bridge_clear_audio_infoframe(struct drm_bridge *bridge) -{ - struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); - struct hdmi *hdmi = hdmi_bridge->hdmi; - u32 val; - - val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0); - val &= ~(HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND | - HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT | - HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE | - HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE); - hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val); - - val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1); - val &= ~HDMI_INFOFRAME_CTRL1_AUDIO_INFO_LINE__MASK; - hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val); - - return 0; -} - -static int msm_hdmi_bridge_clear_spd_infoframe(struct drm_bridge *bridge) -{ - struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); - struct hdmi *hdmi = hdmi_bridge->hdmi; - u32 val; - - val = hdmi_read(hdmi, REG_HDMI_GEN_PKT_CTRL); - val &= ~(HDMI_GEN_PKT_CTRL_GENERIC1_SEND | - HDMI_GEN_PKT_CTRL_GENERIC1_CONT | - HDMI_GEN_PKT_CTRL_GENERIC1_LINE__MASK); - hdmi_write(hdmi, REG_HDMI_GEN_PKT_CTRL, val); - - return 0; -} - -static int msm_hdmi_bridge_clear_hdmi_infoframe(struct drm_bridge *bridge) -{ - struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); - struct hdmi *hdmi = hdmi_bridge->hdmi; - u32 val; - - val = hdmi_read(hdmi, REG_HDMI_GEN_PKT_CTRL); - val &= ~(HDMI_GEN_PKT_CTRL_GENERIC0_SEND | - HDMI_GEN_PKT_CTRL_GENERIC0_CONT | - HDMI_GEN_PKT_CTRL_GENERIC0_UPDATE | - HDMI_GEN_PKT_CTRL_GENERIC0_LINE__MASK); - hdmi_write(hdmi, REG_HDMI_GEN_PKT_CTRL, val); - - return 0; -} - -static int msm_hdmi_bridge_write_avi_infoframe(struct drm_bridge *bridge, - const u8 *buffer, size_t len) -{ - struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); - struct hdmi *hdmi = hdmi_bridge->hdmi; u32 buf[4] = {}; u32 val; int i; @@ -138,8 +67,6 @@ static int msm_hdmi_bridge_write_avi_infoframe(struct drm_bridge *bridge, return -EINVAL; } - msm_hdmi_bridge_clear_avi_infoframe(bridge); - /* * the AVI_INFOx registers don't map exactly to how the AVI infoframes * are packed according to the spec. The checksum from the header is @@ -166,11 +93,9 @@ static int msm_hdmi_bridge_write_avi_infoframe(struct drm_bridge *bridge, return 0; } -static int msm_hdmi_bridge_write_audio_infoframe(struct drm_bridge *bridge, - const u8 *buffer, size_t len) +static int msm_hdmi_config_audio_infoframe(struct hdmi *hdmi, + const u8 *buffer, size_t len) { - struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); - struct hdmi *hdmi = hdmi_bridge->hdmi; u32 val; if (len != HDMI_INFOFRAME_SIZE(AUDIO)) { @@ -179,8 +104,6 @@ static int msm_hdmi_bridge_write_audio_infoframe(struct drm_bridge *bridge, return -EINVAL; } - msm_hdmi_bridge_clear_audio_infoframe(bridge); - hdmi_write(hdmi, REG_HDMI_AUDIO_INFO0, buffer[3] | buffer[4] << 8 | @@ -203,11 +126,9 @@ static int msm_hdmi_bridge_write_audio_infoframe(struct drm_bridge *bridge, return 0; } -static int msm_hdmi_bridge_write_spd_infoframe(struct drm_bridge *bridge, - const u8 *buffer, size_t len) +static int msm_hdmi_config_spd_infoframe(struct hdmi *hdmi, + const u8 *buffer, size_t len) { - struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); - struct hdmi *hdmi = hdmi_bridge->hdmi; u32 buf[7] = {}; u32 val; int i; @@ -218,8 +139,6 @@ static int msm_hdmi_bridge_write_spd_infoframe(struct drm_bridge *bridge, return -EINVAL; } - msm_hdmi_bridge_clear_spd_infoframe(bridge); - /* checksum gets written together with the body of the frame */ hdmi_write(hdmi, REG_HDMI_GENERIC1_HDR, buffer[0] | @@ -240,11 +159,9 @@ static int msm_hdmi_bridge_write_spd_infoframe(struct drm_bridge *bridge, return 0; } -static int msm_hdmi_bridge_write_hdmi_infoframe(struct drm_bridge *bridge, - const u8 *buffer, size_t len) +static int msm_hdmi_config_hdmi_infoframe(struct hdmi *hdmi, + const u8 *buffer, size_t len) { - struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); - struct hdmi *hdmi = hdmi_bridge->hdmi; u32 buf[7] = {}; u32 val; int i; @@ -256,8 +173,6 @@ static int msm_hdmi_bridge_write_hdmi_infoframe(struct drm_bridge *bridge, return -EINVAL; } - msm_hdmi_bridge_clear_hdmi_infoframe(bridge); - /* checksum gets written together with the body of the frame */ hdmi_write(hdmi, REG_HDMI_GENERIC0_HDR, buffer[0] | @@ -279,6 +194,90 @@ static int msm_hdmi_bridge_write_hdmi_infoframe(struct drm_bridge *bridge, return 0; } +static int msm_hdmi_bridge_clear_infoframe(struct drm_bridge *bridge, + enum hdmi_infoframe_type type) +{ + struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); + struct hdmi *hdmi = hdmi_bridge->hdmi; + u32 val; + + switch (type) { + case HDMI_INFOFRAME_TYPE_AVI: + val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0); + val &= ~(HDMI_INFOFRAME_CTRL0_AVI_SEND | + HDMI_INFOFRAME_CTRL0_AVI_CONT); + hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val); + + val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1); + val &= ~HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK; + hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val); + + break; + + case HDMI_INFOFRAME_TYPE_AUDIO: + val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0); + val &= ~(HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND | + HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT | + HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE | + HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE); + hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val); + + val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1); + val &= ~HDMI_INFOFRAME_CTRL1_AUDIO_INFO_LINE__MASK; + hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val); + + break; + + case HDMI_INFOFRAME_TYPE_SPD: + val = hdmi_read(hdmi, REG_HDMI_GEN_PKT_CTRL); + val &= ~(HDMI_GEN_PKT_CTRL_GENERIC1_SEND | + HDMI_GEN_PKT_CTRL_GENERIC1_CONT | + HDMI_GEN_PKT_CTRL_GENERIC1_LINE__MASK); + hdmi_write(hdmi, REG_HDMI_GEN_PKT_CTRL, val); + + break; + + case HDMI_INFOFRAME_TYPE_VENDOR: + val = hdmi_read(hdmi, REG_HDMI_GEN_PKT_CTRL); + val &= ~(HDMI_GEN_PKT_CTRL_GENERIC0_SEND | + HDMI_GEN_PKT_CTRL_GENERIC0_CONT | + HDMI_GEN_PKT_CTRL_GENERIC0_UPDATE | + HDMI_GEN_PKT_CTRL_GENERIC0_LINE__MASK); + hdmi_write(hdmi, REG_HDMI_GEN_PKT_CTRL, val); + + break; + + default: + drm_dbg_driver(hdmi_bridge->base.dev, "Unsupported infoframe type %x\n", type); + } + + return 0; +} + +static int msm_hdmi_bridge_write_infoframe(struct drm_bridge *bridge, + enum hdmi_infoframe_type type, + const u8 *buffer, size_t len) +{ + struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); + struct hdmi *hdmi = hdmi_bridge->hdmi; + + msm_hdmi_bridge_clear_infoframe(bridge, type); + + switch (type) { + case HDMI_INFOFRAME_TYPE_AVI: + return msm_hdmi_config_avi_infoframe(hdmi, buffer, len); + case HDMI_INFOFRAME_TYPE_AUDIO: + return msm_hdmi_config_audio_infoframe(hdmi, buffer, len); + case HDMI_INFOFRAME_TYPE_SPD: + return msm_hdmi_config_spd_infoframe(hdmi, buffer, len); + case HDMI_INFOFRAME_TYPE_VENDOR: + return msm_hdmi_config_hdmi_infoframe(hdmi, buffer, len); + default: + drm_dbg_driver(hdmi_bridge->base.dev, "Unsupported infoframe type %x\n", type); + return 0; + } +} + static void msm_hdmi_set_timings(struct hdmi *hdmi, const struct drm_display_mode *mode); @@ -463,14 +462,8 @@ static const struct drm_bridge_funcs msm_hdmi_bridge_funcs = { .hpd_enable = msm_hdmi_hpd_enable, .hpd_disable = msm_hdmi_hpd_disable, .hdmi_tmds_char_rate_valid = msm_hdmi_bridge_tmds_char_rate_valid, - .hdmi_clear_audio_infoframe = msm_hdmi_bridge_clear_audio_infoframe, - .hdmi_write_audio_infoframe = msm_hdmi_bridge_write_audio_infoframe, - .hdmi_clear_avi_infoframe = msm_hdmi_bridge_clear_avi_infoframe, - .hdmi_write_avi_infoframe = msm_hdmi_bridge_write_avi_infoframe, - .hdmi_clear_spd_infoframe = msm_hdmi_bridge_clear_spd_infoframe, - .hdmi_write_spd_infoframe = msm_hdmi_bridge_write_spd_infoframe, - .hdmi_clear_hdmi_infoframe = msm_hdmi_bridge_clear_hdmi_infoframe, - .hdmi_write_hdmi_infoframe = msm_hdmi_bridge_write_hdmi_infoframe, + .hdmi_clear_infoframe = msm_hdmi_bridge_clear_infoframe, + .hdmi_write_infoframe = msm_hdmi_bridge_write_infoframe, .hdmi_audio_prepare = msm_hdmi_bridge_audio_prepare, .hdmi_audio_shutdown = msm_hdmi_bridge_audio_shutdown, }; diff --git a/drivers/gpu/drm/rockchip/rk3066_hdmi.c b/drivers/gpu/drm/rockchip/rk3066_hdmi.c index 6e7d13b139868..ae4a5ac2299a9 100644 --- a/drivers/gpu/drm/rockchip/rk3066_hdmi.c +++ b/drivers/gpu/drm/rockchip/rk3066_hdmi.c @@ -157,33 +157,35 @@ static void rk3066_hdmi_set_power_mode(struct rk3066_hdmi *hdmi, int mode) hdmi->tmdsclk = DEFAULT_PLLA_RATE; } -static int rk3066_hdmi_bridge_clear_avi_infoframe(struct drm_bridge *bridge) +static int rk3066_hdmi_bridge_clear_infoframe(struct drm_bridge *bridge, + enum hdmi_infoframe_type type) { struct rk3066_hdmi *hdmi = bridge_to_rk3066_hdmi(bridge); - hdmi_writeb(hdmi, HDMI_CP_BUF_INDEX, HDMI_INFOFRAME_AVI); - - return 0; -} - -static int -rk3066_hdmi_bridge_clear_hdmi_infoframe(struct drm_bridge *bridge) -{ - /* FIXME: add support for this InfoFrame */ + if (type != HDMI_INFOFRAME_TYPE_AVI) { + drm_err(bridge->dev, "Unsupported infoframe type: %u\n", type); + return 0; + } - drm_warn_once(bridge->encoder->dev, "HDMI VSI not supported\n"); + hdmi_writeb(hdmi, HDMI_CP_BUF_INDEX, HDMI_INFOFRAME_AVI); return 0; } static int -rk3066_hdmi_bridge_write_avi_infoframe(struct drm_bridge *bridge, - const u8 *buffer, size_t len) +rk3066_hdmi_bridge_write_infoframe(struct drm_bridge *bridge, + enum hdmi_infoframe_type type, + const u8 *buffer, size_t len) { struct rk3066_hdmi *hdmi = bridge_to_rk3066_hdmi(bridge); ssize_t i; - rk3066_hdmi_bridge_clear_avi_infoframe(bridge); + if (type != HDMI_INFOFRAME_TYPE_AVI) { + drm_err(bridge->dev, "Unsupported infoframe type: %u\n", type); + return 0; + } + + rk3066_hdmi_bridge_clear_infoframe(bridge, type); for (i = 0; i < len; i++) hdmi_writeb(hdmi, HDMI_CP_BUF_ACC_HB0 + i * 4, buffer[i]); @@ -191,17 +193,6 @@ rk3066_hdmi_bridge_write_avi_infoframe(struct drm_bridge *bridge, return 0; } -static int -rk3066_hdmi_bridge_write_hdmi_infoframe(struct drm_bridge *bridge, - const u8 *buffer, size_t len) -{ - rk3066_hdmi_bridge_clear_hdmi_infoframe(bridge); - - /* FIXME: add support for this InfoFrame */ - - return 0; -} - static int rk3066_hdmi_config_video_timing(struct rk3066_hdmi *hdmi, struct drm_display_mode *mode) { @@ -501,10 +492,8 @@ static const struct drm_bridge_funcs rk3066_hdmi_bridge_funcs = { .atomic_disable = rk3066_hdmi_bridge_atomic_disable, .detect = rk3066_hdmi_bridge_detect, .edid_read = rk3066_hdmi_bridge_edid_read, - .hdmi_clear_avi_infoframe = rk3066_hdmi_bridge_clear_avi_infoframe, - .hdmi_write_avi_infoframe = rk3066_hdmi_bridge_write_avi_infoframe, - .hdmi_clear_hdmi_infoframe = rk3066_hdmi_bridge_clear_hdmi_infoframe, - .hdmi_write_hdmi_infoframe = rk3066_hdmi_bridge_write_hdmi_infoframe, + .hdmi_clear_infoframe = rk3066_hdmi_bridge_clear_infoframe, + .hdmi_write_infoframe = rk3066_hdmi_bridge_write_infoframe, .mode_valid = rk3066_hdmi_bridge_mode_valid, }; diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index d2d3d759eec20..8bfea1e0a62d9 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -667,113 +667,29 @@ struct drm_bridge_funcs { unsigned long long tmds_rate); /** - * @hdmi_clear_avi_infoframe: + * @hdmi_clear_infoframe: * * This callback clears the infoframes in the hardware during commit. + * It will be called multiple times, once for every disabled infoframe + * type. * * This callback is optional but it must be implemented by bridges that * set the DRM_BRIDGE_OP_HDMI flag in their &drm_bridge->ops. */ - int (*hdmi_clear_avi_infoframe)(struct drm_bridge *bridge); - - /** - * @hdmi_write_avi_infoframe: - * - * Program the infoframe into the hardware. - * - * This callback is optional but it must be implemented by bridges that - * set the DRM_BRIDGE_OP_HDMI flag in their &drm_bridge->ops. - */ - int (*hdmi_write_avi_infoframe)(struct drm_bridge *bridge, - const u8 *buffer, size_t len); - - /** - * @hdmi_clear_hdmi_infoframe: - * - * This callback clears the infoframes in the hardware during commit. - * - * This callback is optional but it must be implemented by bridges that - * set the DRM_BRIDGE_OP_HDMI flag in their &drm_bridge->ops. - */ - int (*hdmi_clear_hdmi_infoframe)(struct drm_bridge *bridge); - + int (*hdmi_clear_infoframe)(struct drm_bridge *bridge, + enum hdmi_infoframe_type type); /** - * @hdmi_write_hdmi_infoframe: + * @hdmi_write_infoframe: * - * Program the infoframe into the hardware. + * Program the infoframe into the hardware. It will be called multiple + * times, once for every updated infoframe type. * * This callback is optional but it must be implemented by bridges that * set the DRM_BRIDGE_OP_HDMI flag in their &drm_bridge->ops. */ - int (*hdmi_write_hdmi_infoframe)(struct drm_bridge *bridge, - const u8 *buffer, size_t len); - - /** - * @hdmi_clear_hdr_drm_infoframe: - * - * This callback clears the infoframes in the hardware during commit. - * - * This callback is optional but it must be implemented by bridges that - * set the DRM_BRIDGE_OP_HDMI_HDR_DRM_INFOFRAME flag in their - * &drm_bridge->ops. - */ - int (*hdmi_clear_hdr_drm_infoframe)(struct drm_bridge *bridge); - - /** - * @hdmi_write_hdr_drm_infoframe: - * - * Program the infoframe into the hardware. - * - * This callback is optional but it must be implemented by bridges that - * set the DRM_BRIDGE_OP_HDMI_HDR_DRM_INFOFRAME flag in their - * &drm_bridge->ops. - */ - int (*hdmi_write_hdr_drm_infoframe)(struct drm_bridge *bridge, - const u8 *buffer, size_t len); - - /** - * @hdmi_clear_spd_infoframe: - * - * This callback clears the infoframes in the hardware during commit. - * - * This callback is optional but it must be implemented by bridges that - * set the DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME flag in their - * &drm_bridge->ops. - */ - int (*hdmi_clear_spd_infoframe)(struct drm_bridge *bridge); - - /** - * @hdmi_write_spd_infoframe: - * - * Program the infoframe into the hardware. - * - * This callback is optional but it must be implemented by bridges that - * set the DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME flag in their - * &drm_bridge->ops. - */ - int (*hdmi_write_spd_infoframe)(struct drm_bridge *bridge, - const u8 *buffer, size_t len); - - /** - * @hdmi_clear_audio_infoframe: - * - * This callback clears the infoframes in the hardware during commit. - * - * This callback is optional but it must be implemented by bridges that - * set the DRM_BRIDGE_OP_HDMI_AUDIO flag in their &drm_bridge->ops. - */ - int (*hdmi_clear_audio_infoframe)(struct drm_bridge *bridge); - - /** - * @hdmi_write_audio_infoframe: - * - * Program the infoframe into the hardware. - * - * This callback is optional but it must be implemented by bridges that - * set the DRM_BRIDGE_OP_HDMI_AUDIO flag in their &drm_bridge->ops. - */ - int (*hdmi_write_audio_infoframe)(struct drm_bridge *bridge, - const u8 *buffer, size_t len); + int (*hdmi_write_infoframe)(struct drm_bridge *bridge, + enum hdmi_infoframe_type type, + const u8 *buffer, size_t len); /** * @hdmi_audio_startup: @@ -1029,11 +945,7 @@ enum drm_bridge_ops { /** * @DRM_BRIDGE_OP_HDMI: The bridge provides HDMI connector operations, * including infoframes support. Bridges that set this flag must - * provide HDMI-related information and implement the - * &drm_bridge_funcs->clear_avi_infoframe, - * &drm_bridge_funcs->write_avi_infoframe, - * &drm_bridge_funcs->clear_hdmi_infoframe and - * &drm_bridge_funcs->write_hdmi_infoframe callbacks. + * implement the &drm_bridge_funcs->write_infoframe callback. * * Note: currently there can be at most one bridge in a chain that sets * this bit. This is to simplify corresponding glue code in connector @@ -1045,9 +957,6 @@ enum drm_bridge_ops { * Bridges that set this flag must implement the * &drm_bridge_funcs->hdmi_audio_prepare and * &drm_bridge_funcs->hdmi_audio_shutdown callbacks. - * If the bridge implements @DRM_BRIDGE_OP_HDMI, it also must implement - * &drm_bridge_funcs->hdmi_write_audio_infoframe and - * &drm_bridge_funcs->hdmi_cleaer_audio_infoframe callbacks. * * Note: currently there can be at most one bridge in a chain that sets * this bit. This is to simplify corresponding glue code in connector @@ -1079,18 +988,6 @@ enum drm_bridge_ops { * to be present. */ DRM_BRIDGE_OP_HDMI_CEC_ADAPTER = BIT(8), - /** - * @DRM_BRIDGE_OP_HDMI_HDR_DRM_INFOFRAME: The bridge supports - * &drm_bridge_funcs->hdmi_write_hdr_drm_infoframe and - * &drm_bridge_funcs->hdmi_clear_hdr_drm_infoframe callbacks. - */ - DRM_BRIDGE_OP_HDMI_HDR_DRM_INFOFRAME = BIT(9), - /** - * @DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME: The bridge supports - * &drm_bridge_funcs->hdmi_write_spd_infoframe and - * &drm_bridge_funcs->hdmi_clear_spd_infoframe callbacks. - */ - DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME = BIT(10), }; /** From 4f2d1efb2eb54d8973ccc0f355a293082debab00 Mon Sep 17 00:00:00 2001 From: Salendarsingh Gaud Date: Mon, 13 Jul 2026 21:15:55 +0530 Subject: [PATCH 14/14] Revert "BACKPORT: drm/bridge: add next_bridge pointer to struct drm_bridge" Reverting as the dependency change is NAKed. This reverts commit 22affbca0818cce5ddaa6c8d67186867fe87a32e. Signed-off-by: Salendarsingh Gaud --- drivers/gpu/drm/drm_bridge.c | 3 --- include/drm/drm_bridge.h | 11 ----------- 2 files changed, 14 deletions(-) diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index 8282434a68e79..d031447eebc95 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -206,9 +206,6 @@ static void __drm_bridge_free(struct kref *kref) if (bridge->funcs->destroy) bridge->funcs->destroy(bridge); - - drm_bridge_put(bridge->next_bridge); - kfree(bridge->container); } diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index 8bfea1e0a62d9..57d9a3c062124 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -1153,17 +1153,6 @@ struct drm_bridge { * @hpd_cb. */ void *hpd_data; - - /** - * @next_bridge: Pointer to the following bridge, automatically put - * when this bridge is freed (i.e. at destroy time). This is for - * drivers needing to store a pointer to the next bridge in the - * chain, and ensures any code still holding a reference to this - * bridge after its removal cannot use-after-free the next - * bridge. Any other bridge pointers stored by the driver must be - * put in the .destroy callback by driver code. - */ - struct drm_bridge *next_bridge; }; static inline struct drm_bridge *