While LT9611UXC is a DSI-to-HDMI bridge, it implements all HDMI-related functions internally, in the firmware. Implement DRM_BRIDGE_OP_HDMI and DRM_BRIDGE_OP_HDMI_AUDIO by providing necessary stubs, streamlining HDMI and HDMI audio plumbing (which includes plugged notifications and ELD handling).
Signed-off-by: Dmitry Baryshkov <dmitry.barysh...@oss.qualcomm.com> --- drivers/gpu/drm/bridge/lontium-lt9611uxc.c | 130 ++++++++++++----------------- 1 file changed, 54 insertions(+), 76 deletions(-) diff --git a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c index 38fb8776c0f441ae433c60a7680aaa6501a8956e..df4661986423a871c006af2a36d85d8103935f93 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c @@ -17,8 +17,6 @@ #include <linux/wait.h> #include <linux/workqueue.h> -#include <sound/hdmi-codec.h> - #include <drm/drm_atomic_helper.h> #include <drm/drm_bridge.h> #include <drm/drm_edid.h> @@ -27,6 +25,8 @@ #include <drm/drm_print.h> #include <drm/drm_probe_helper.h> +#include <drm/display/drm_hdmi_audio_helper.h> + #define EDID_BLOCK_SIZE 128 #define EDID_NUM_BLOCKS 2 @@ -48,7 +48,6 @@ struct lt9611uxc { struct device_node *dsi1_node; struct mipi_dsi_device *dsi0; struct mipi_dsi_device *dsi1; - struct platform_device *audio_pdev; struct gpio_desc *reset_gpio; struct gpio_desc *enable_gpio; @@ -429,12 +428,50 @@ static const struct drm_edid *lt9611uxc_bridge_edid_read(struct drm_bridge *brid return drm_edid_read_custom(connector, lt9611uxc_get_edid_block, lt9611uxc); } +static int lt9611uxc_hdmi_clear_infoframe(struct drm_bridge *bridge, + enum hdmi_infoframe_type type) +{ + /* LT9611UXC managed infoframes in the firmware, provide an empty stub */ + return 0; +} + +static int lt9611uxc_hdmi_write_infoframe(struct drm_bridge *bridge, + enum hdmi_infoframe_type type, + const u8 *buffer, size_t len) +{ + /* LT9611UXC managed infoframes in the firmware, provide an empty stub */ + return 0; +} + +static int lt9611uxc_hdmi_audio_prepare(struct drm_bridge *bridge, + struct drm_connector *connector, + struct hdmi_codec_daifmt *fmt, + struct hdmi_codec_params *hparms) +{ + /* + * LT9611UXC will automatically detect rate and sample size, so no need + * to setup anything here. + */ + return 0; +} + +static void lt9611uxc_hdmi_audio_shutdown(struct drm_bridge *bridge, + struct drm_connector *connector) +{ +} + static const struct drm_bridge_funcs lt9611uxc_bridge_funcs = { .attach = lt9611uxc_bridge_attach, .mode_valid = lt9611uxc_bridge_mode_valid, .mode_set = lt9611uxc_bridge_mode_set, .detect = lt9611uxc_bridge_detect, .edid_read = lt9611uxc_bridge_edid_read, + + .hdmi_write_infoframe = lt9611uxc_hdmi_write_infoframe, + .hdmi_clear_infoframe = lt9611uxc_hdmi_clear_infoframe, + + .hdmi_audio_prepare = lt9611uxc_hdmi_audio_prepare, + .hdmi_audio_shutdown = lt9611uxc_hdmi_audio_shutdown, }; static int lt9611uxc_parse_dt(struct device *dev, @@ -508,73 +545,6 @@ static int lt9611uxc_read_version(struct lt9611uxc *lt9611uxc) return ret < 0 ? ret : rev; } -static int lt9611uxc_hdmi_hw_params(struct device *dev, void *data, - struct hdmi_codec_daifmt *fmt, - struct hdmi_codec_params *hparms) -{ - /* - * LT9611UXC will automatically detect rate and sample size, so no need - * to setup anything here. - */ - return 0; -} - -static void lt9611uxc_audio_shutdown(struct device *dev, void *data) -{ -} - -static int lt9611uxc_hdmi_i2s_get_dai_id(struct snd_soc_component *component, - struct device_node *endpoint, - void *data) -{ - struct of_endpoint of_ep; - int ret; - - ret = of_graph_parse_endpoint(endpoint, &of_ep); - if (ret < 0) - return ret; - - /* - * HDMI sound should be located as reg = <2> - * Then, it is sound port 0 - */ - if (of_ep.port == 2) - return 0; - - return -EINVAL; -} - -static const struct hdmi_codec_ops lt9611uxc_codec_ops = { - .hw_params = lt9611uxc_hdmi_hw_params, - .audio_shutdown = lt9611uxc_audio_shutdown, - .get_dai_id = lt9611uxc_hdmi_i2s_get_dai_id, -}; - -static int lt9611uxc_audio_init(struct device *dev, struct lt9611uxc *lt9611uxc) -{ - struct hdmi_codec_pdata codec_data = { - .ops = <9611uxc_codec_ops, - .max_i2s_channels = 2, - .i2s = 1, - .data = lt9611uxc, - }; - - lt9611uxc->audio_pdev = - platform_device_register_data(dev, HDMI_CODEC_DRV_NAME, - PLATFORM_DEVID_AUTO, - &codec_data, sizeof(codec_data)); - - return PTR_ERR_OR_ZERO(lt9611uxc->audio_pdev); -} - -static void lt9611uxc_audio_exit(struct lt9611uxc *lt9611uxc) -{ - if (lt9611uxc->audio_pdev) { - platform_device_unregister(lt9611uxc->audio_pdev); - lt9611uxc->audio_pdev = NULL; - } -} - #define LT9611UXC_FW_PAGE_SIZE 32 static void lt9611uxc_firmware_write_page(struct lt9611uxc *lt9611uxc, u16 addr, const u8 *buf) { @@ -858,11 +828,24 @@ static int lt9611uxc_probe(struct i2c_client *client) i2c_set_clientdata(client, lt9611uxc); lt9611uxc->bridge.of_node = client->dev.of_node; - lt9611uxc->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID; + lt9611uxc->bridge.ops = DRM_BRIDGE_OP_DETECT | + DRM_BRIDGE_OP_EDID | + DRM_BRIDGE_OP_HDMI | + DRM_BRIDGE_OP_HDMI_AUDIO; if (lt9611uxc->hpd_supported) lt9611uxc->bridge.ops |= DRM_BRIDGE_OP_HPD; lt9611uxc->bridge.type = DRM_MODE_CONNECTOR_HDMIA; + lt9611uxc->bridge.vendor = "Lontium"; + lt9611uxc->bridge.product = "LT9611UXC"; + lt9611uxc->bridge.autogenerated_infoframes = + DRM_CONNECTOR_INFOFRAME_AUDIO | + DRM_CONNECTOR_INFOFRAME_AVI; + + lt9611uxc->bridge.hdmi_audio_dev = dev; + lt9611uxc->bridge.hdmi_audio_max_i2s_playback_channels = 2; + lt9611uxc->bridge.hdmi_audio_dai_port = 2; + drm_bridge_add(<9611uxc->bridge); /* Attach primary DSI */ @@ -881,10 +864,6 @@ static int lt9611uxc_probe(struct i2c_client *client) } } - ret = lt9611uxc_audio_init(dev, lt9611uxc); - if (ret) - goto err_remove_bridge; - return 0; err_remove_bridge: @@ -908,7 +887,6 @@ static void lt9611uxc_remove(struct i2c_client *client) free_irq(client->irq, lt9611uxc); cancel_work_sync(<9611uxc->work); - lt9611uxc_audio_exit(lt9611uxc); drm_bridge_remove(<9611uxc->bridge); mutex_destroy(<9611uxc->ocm_lock); -- 2.47.2