Loading drivers/video/fbdev/msm/mdss_hdmi_tx.c +102 −99 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ #include <linux/types.h> #include <linux/hdcp_qseecom.h> #include <linux/msm_mdp.h> #include <linux/msm_ext_display.h> #define REG_DUMP 0 Loading Loading @@ -414,7 +415,6 @@ static inline void hdmi_tx_cec_device_suspend(struct hdmi_tx_ctrl *hdmi_ctrl) hdmi_cec_device_suspend(fd, hdmi_ctrl->panel_suspend); } static inline void hdmi_tx_send_cable_notification( struct hdmi_tx_ctrl *hdmi_ctrl, int val) { Loading @@ -431,7 +431,7 @@ static inline void hdmi_tx_send_cable_notification( } } static inline void hdmi_tx_set_audio_switch_node( static inline void hdmi_tx_ack_state( struct hdmi_tx_ctrl *hdmi_ctrl, int val) { if (hdmi_ctrl && hdmi_ctrl->ext_audio_data.intf_ops.notify && Loading @@ -440,47 +440,6 @@ static inline void hdmi_tx_set_audio_switch_node( val); } static void hdmi_tx_wait_for_audio_engine(struct hdmi_tx_ctrl *hdmi_ctrl) { u64 status = 0; u32 wait_for_vote = 50; struct dss_io_data *io = NULL; if (!hdmi_ctrl) { DEV_ERR("%s: invalid input\n", __func__); return; } io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO]; if (!io->base) { DEV_ERR("%s: core io not inititalized\n", __func__); return; } /* * wait for 5 sec max for audio engine to acknowledge if hdmi tx core * can be safely turned off. Sleep for a reasonable time to make sure * vote_hdmi_core_on variable is updated properly by audio. */ while (hdmi_ctrl->vote_hdmi_core_on && --wait_for_vote) msleep(100); if (!wait_for_vote) DEV_ERR("%s: HDMI core still voted for power on\n", __func__); if (readl_poll_timeout(io->base + HDMI_AUDIO_PKT_CTRL, status, (status & BIT(0)) == 0, AUDIO_POLL_SLEEP_US, AUDIO_POLL_TIMEOUT_US)) DEV_ERR("%s: Error turning off audio packet transmission.\n", __func__); if (readl_poll_timeout(io->base + HDMI_AUDIO_CFG, status, (status & BIT(0)) == 0, AUDIO_POLL_SLEEP_US, AUDIO_POLL_TIMEOUT_US)) DEV_ERR("%s: Error turning off audio engine.\n", __func__); } static struct hdmi_tx_ctrl *hdmi_tx_get_drvdata_from_panel_data( struct mdss_panel_data *mpd) { Loading Loading @@ -900,8 +859,7 @@ static ssize_t hdmi_tx_sysfs_wta_hpd(struct device *dev, hdmi_tx_config_5v(hdmi_ctrl, false); } else { hdmi_tx_hpd_off(hdmi_ctrl); hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0); hdmi_tx_send_cable_notification(hdmi_ctrl, 0); } break; Loading Loading @@ -1589,7 +1547,6 @@ static void hdmi_tx_hdcp_cb_work(struct work_struct *work) if (hdmi_tx_is_panel_on(hdmi_ctrl) && hdmi_tx_is_stream_shareable(hdmi_ctrl)) { rc = hdmi_tx_config_avmute(hdmi_ctrl, false); hdmi_tx_set_audio_switch_node(hdmi_ctrl, 1); } if (hdmi_ctrl->hdcp1_use_sw_keys && hdmi_ctrl->hdcp14_present) Loading @@ -1605,7 +1562,6 @@ static void hdmi_tx_hdcp_cb_work(struct work_struct *work) if (hdmi_tx_is_encryption_set(hdmi_ctrl) || !hdmi_tx_is_stream_shareable(hdmi_ctrl)) { hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0); rc = hdmi_tx_config_avmute(hdmi_ctrl, true); } Loading @@ -1631,7 +1587,6 @@ static void hdmi_tx_hdcp_cb_work(struct work_struct *work) if (hdmi_tx_is_panel_on(hdmi_ctrl)) { rc = hdmi_tx_config_avmute(hdmi_ctrl, false); hdmi_tx_set_audio_switch_node(hdmi_ctrl, 1); } break; case HDCP_STATE_AUTH_ENC_1X: Loading @@ -1641,9 +1596,7 @@ static void hdmi_tx_hdcp_cb_work(struct work_struct *work) if (hdmi_tx_is_panel_on(hdmi_ctrl) && hdmi_tx_is_stream_shareable(hdmi_ctrl)) { rc = hdmi_tx_config_avmute(hdmi_ctrl, false); hdmi_tx_set_audio_switch_node(hdmi_ctrl, 1); } else { hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0); rc = hdmi_tx_config_avmute(hdmi_ctrl, true); } break; Loading Loading @@ -2373,7 +2326,8 @@ static void hdmi_tx_hpd_int_work(struct work_struct *work) if (!hdmi_ctrl->hpd_initialized) { DEV_DBG("hpd not initialized\n"); goto end; mutex_unlock(&hdmi_ctrl->tx_lock); return; } DEV_DBG("%s: %s\n", __func__, Loading @@ -2386,16 +2340,11 @@ static void hdmi_tx_hpd_int_work(struct work_struct *work) pr_warn_ratelimited("%s: EDID read failed\n", __func__); hdmi_tx_update_deep_color(hdmi_ctrl); hdmi_tx_update_hdr_info(hdmi_ctrl); hdmi_tx_send_cable_notification(hdmi_ctrl, true); } else { hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0); hdmi_tx_wait_for_audio_engine(hdmi_ctrl); hdmi_tx_send_cable_notification(hdmi_ctrl, false); } end: mutex_unlock(&hdmi_ctrl->tx_lock); hdmi_tx_send_cable_notification(hdmi_ctrl, hdmi_ctrl->hpd_state); } /* hdmi_tx_hpd_int_work */ static int hdmi_tx_check_capability(struct hdmi_tx_ctrl *hdmi_ctrl) Loading Loading @@ -3239,7 +3188,6 @@ static int hdmi_tx_power_on(struct hdmi_tx_ctrl *hdmi_ctrl) if (hdmi_ctrl->panel.infoframe && !hdmi_tx_is_encryption_set(hdmi_ctrl) && hdmi_tx_is_stream_shareable(hdmi_ctrl)) { hdmi_tx_set_audio_switch_node(hdmi_ctrl, 1); hdmi_tx_config_avmute(hdmi_ctrl, false); } Loading Loading @@ -3845,20 +3793,6 @@ static int hdmi_tx_evt_handle_resume(struct hdmi_tx_ctrl *hdmi_ctrl) goto end; } if (hdmi_ctrl->sdev.state && !hdmi_tx_hw_is_cable_connected(hdmi_ctrl)) { u32 timeout; reinit_completion(&hdmi_ctrl->hpd_int_done); timeout = wait_for_completion_timeout( &hdmi_ctrl->hpd_int_done, HZ/10); if (!timeout && !hdmi_ctrl->hpd_state) { DEV_DBG("%s: cable removed during suspend\n", __func__); hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0); hdmi_tx_wait_for_audio_engine(hdmi_ctrl); hdmi_tx_send_cable_notification(hdmi_ctrl, 0); } } end: return rc; } Loading Loading @@ -3906,14 +3840,6 @@ static int hdmi_tx_evt_handle_panel_on(struct hdmi_tx_ctrl *hdmi_ctrl) hdmi_ctrl->timing_gen_on = true; if (hdmi_ctrl->panel_suspend) { DEV_DBG("%s: panel suspend has triggered\n", __func__); hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0); hdmi_tx_wait_for_audio_engine(hdmi_ctrl); hdmi_tx_send_cable_notification(hdmi_ctrl, 0); } return rc; } Loading Loading @@ -4003,6 +3929,55 @@ static int hdmi_tx_evt_handle_hdmi_ppm(struct hdmi_tx_ctrl *hdmi_ctrl) return hdmi_tx_update_ppm(hdmi_ctrl, ppm); } static int hdmi_tx_pre_evt_handle_panel_off(struct hdmi_tx_ctrl *hdmi_ctrl) { hdmi_tx_ack_state(hdmi_ctrl, false); return 0; } static int hdmi_tx_pre_evt_handle_update_fps(struct hdmi_tx_ctrl *hdmi_ctrl) { hdmi_ctrl->dynamic_fps = (u32) (unsigned long)hdmi_ctrl->evt_arg; queue_work(hdmi_ctrl->workq, &hdmi_ctrl->fps_work); return 0; } static int hdmi_tx_post_evt_handle_unblank(struct hdmi_tx_ctrl *hdmi_ctrl) { hdmi_tx_ack_state(hdmi_ctrl, true); return 0; } static int hdmi_tx_post_evt_handle_resume(struct hdmi_tx_ctrl *hdmi_ctrl) { if (!hdmi_ctrl->hpd_feature_on) return 0; if (!hdmi_tx_hw_is_cable_connected(hdmi_ctrl)) { u32 timeout; reinit_completion(&hdmi_ctrl->hpd_int_done); timeout = wait_for_completion_timeout( &hdmi_ctrl->hpd_int_done, HZ/10); if (!timeout) { pr_debug("cable removed during suspend\n"); hdmi_tx_send_cable_notification(hdmi_ctrl, 0); } } return 0; } static int hdmi_tx_post_evt_handle_panel_on(struct hdmi_tx_ctrl *hdmi_ctrl) { if (hdmi_ctrl->panel_suspend) { pr_debug("panel suspend has triggered\n"); hdmi_tx_send_cable_notification(hdmi_ctrl, 0); } return 0; } static int hdmi_tx_event_handler(struct mdss_panel_data *panel_data, int event, void *arg) { Loading @@ -4012,33 +3987,52 @@ static int hdmi_tx_event_handler(struct mdss_panel_data *panel_data, hdmi_tx_get_drvdata_from_panel_data(panel_data); if (!hdmi_ctrl) { DEV_ERR("%s: invalid input\n", __func__); rc = -EINVAL; goto end; } /* UPDATE FPS is called from atomic context */ if (event == MDSS_EVENT_PANEL_UPDATE_FPS) { hdmi_ctrl->dynamic_fps = (u32) (unsigned long)arg; queue_work(hdmi_ctrl->workq, &hdmi_ctrl->fps_work); return rc; pr_err("%s: invalid input\n", __func__); return -EINVAL; } mutex_lock(&hdmi_ctrl->tx_lock); hdmi_ctrl->evt_arg = arg; DEV_DBG("%s: event = %s suspend=%d, hpd_feature=%d\n", __func__, pr_debug("event = %s suspend=%d, hpd_feature=%d\n", mdss_panel_intf_event_to_string(event), hdmi_ctrl->panel_suspend, hdmi_ctrl->hpd_feature_on); /* event handlers prior to tx_lock */ handler = hdmi_ctrl->pre_evt_handler[event]; if (handler) { rc = handler(hdmi_ctrl); if (rc) { pr_err("pre handler failed: event = %s, rc = %d\n", mdss_panel_intf_event_to_string(event), rc); return rc; } } mutex_lock(&hdmi_ctrl->tx_lock); handler = hdmi_ctrl->evt_handler[event]; if (handler) if (handler) { rc = handler(hdmi_ctrl); if (rc) { pr_err("handler failed: event = %s, rc = %d\n", mdss_panel_intf_event_to_string(event), rc); mutex_unlock(&hdmi_ctrl->tx_lock); return rc; } } mutex_unlock(&hdmi_ctrl->tx_lock); end: /* event handlers post to tx_lock */ handler = hdmi_ctrl->post_evt_handler[event]; if (handler) { rc = handler(hdmi_ctrl); if (rc) pr_err("post handler failed: event = %s, rc = %d\n", mdss_panel_intf_event_to_string(event), rc); } return rc; } Loading Loading @@ -4692,7 +4686,6 @@ static int hdmi_tx_init_event_handler(struct hdmi_tx_ctrl *hdmi_ctrl) return -EINVAL; handler = hdmi_ctrl->evt_handler; handler[MDSS_EVENT_FB_REGISTERED] = hdmi_tx_evt_handle_register; handler[MDSS_EVENT_CHECK_PARAMS] = hdmi_tx_evt_handle_check_param; handler[MDSS_EVENT_RESUME] = hdmi_tx_evt_handle_resume; Loading @@ -4706,6 +4699,16 @@ static int hdmi_tx_init_event_handler(struct hdmi_tx_ctrl *hdmi_ctrl) handler[MDSS_EVENT_DEEP_COLOR] = hdmi_tx_evt_handle_deep_color; handler[MDSS_EVENT_UPDATE_PANEL_PPM] = hdmi_tx_evt_handle_hdmi_ppm; handler = hdmi_ctrl->pre_evt_handler; handler[MDSS_EVENT_PANEL_UPDATE_FPS] = hdmi_tx_pre_evt_handle_update_fps; handler[MDSS_EVENT_PANEL_OFF] = hdmi_tx_pre_evt_handle_panel_off; handler = hdmi_ctrl->post_evt_handler; handler[MDSS_EVENT_UNBLANK] = hdmi_tx_post_evt_handle_unblank; handler[MDSS_EVENT_RESUME] = hdmi_tx_post_evt_handle_resume; handler[MDSS_EVENT_PANEL_ON] = hdmi_tx_post_evt_handle_panel_on; return 0; } Loading drivers/video/fbdev/msm/mdss_hdmi_tx.h +3 −1 Original line number Diff line number Diff line Loading @@ -98,7 +98,6 @@ struct hdmi_tx_ctrl { struct mutex tx_lock; struct list_head cable_notify_handlers; struct kobject *kobj; struct switch_dev sdev; struct workqueue_struct *workq; struct hdmi_util_ds_data ds_data; struct completion hpd_int_done; Loading Loading @@ -166,7 +165,10 @@ struct hdmi_tx_ctrl { char disp_switch_name[MAX_SWITCH_NAME_SIZE]; /* pre/post is done in the context without tx_lock */ hdmi_tx_evt_handler pre_evt_handler[MDSS_EVENT_MAX - 1]; hdmi_tx_evt_handler evt_handler[MDSS_EVENT_MAX - 1]; hdmi_tx_evt_handler post_evt_handler[MDSS_EVENT_MAX - 1]; }; #endif /* __MDSS_HDMI_TX_H__ */ include/linux/msm_ext_display.h +2 −3 Original line number Diff line number Diff line Loading @@ -91,7 +91,7 @@ enum msm_ext_disp_power_state { /** * struct msm_ext_disp_intf_ops - operations exposed to display interface * @hpd: updates external display interface state * @notify: updates audio framework with interface state * @notify: acknowledgment to power on or off */ struct msm_ext_disp_intf_ops { int (*hpd)(struct platform_device *pdev, Loading @@ -100,8 +100,7 @@ struct msm_ext_disp_intf_ops { u32 flags); int (*notify)(struct platform_device *pdev, enum msm_ext_disp_cable_state state); int (*ack)(struct platform_device *pdev, u32 ack); int (*ack)(struct platform_device *pdev, u32 ack); }; /** Loading Loading
drivers/video/fbdev/msm/mdss_hdmi_tx.c +102 −99 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ #include <linux/types.h> #include <linux/hdcp_qseecom.h> #include <linux/msm_mdp.h> #include <linux/msm_ext_display.h> #define REG_DUMP 0 Loading Loading @@ -414,7 +415,6 @@ static inline void hdmi_tx_cec_device_suspend(struct hdmi_tx_ctrl *hdmi_ctrl) hdmi_cec_device_suspend(fd, hdmi_ctrl->panel_suspend); } static inline void hdmi_tx_send_cable_notification( struct hdmi_tx_ctrl *hdmi_ctrl, int val) { Loading @@ -431,7 +431,7 @@ static inline void hdmi_tx_send_cable_notification( } } static inline void hdmi_tx_set_audio_switch_node( static inline void hdmi_tx_ack_state( struct hdmi_tx_ctrl *hdmi_ctrl, int val) { if (hdmi_ctrl && hdmi_ctrl->ext_audio_data.intf_ops.notify && Loading @@ -440,47 +440,6 @@ static inline void hdmi_tx_set_audio_switch_node( val); } static void hdmi_tx_wait_for_audio_engine(struct hdmi_tx_ctrl *hdmi_ctrl) { u64 status = 0; u32 wait_for_vote = 50; struct dss_io_data *io = NULL; if (!hdmi_ctrl) { DEV_ERR("%s: invalid input\n", __func__); return; } io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO]; if (!io->base) { DEV_ERR("%s: core io not inititalized\n", __func__); return; } /* * wait for 5 sec max for audio engine to acknowledge if hdmi tx core * can be safely turned off. Sleep for a reasonable time to make sure * vote_hdmi_core_on variable is updated properly by audio. */ while (hdmi_ctrl->vote_hdmi_core_on && --wait_for_vote) msleep(100); if (!wait_for_vote) DEV_ERR("%s: HDMI core still voted for power on\n", __func__); if (readl_poll_timeout(io->base + HDMI_AUDIO_PKT_CTRL, status, (status & BIT(0)) == 0, AUDIO_POLL_SLEEP_US, AUDIO_POLL_TIMEOUT_US)) DEV_ERR("%s: Error turning off audio packet transmission.\n", __func__); if (readl_poll_timeout(io->base + HDMI_AUDIO_CFG, status, (status & BIT(0)) == 0, AUDIO_POLL_SLEEP_US, AUDIO_POLL_TIMEOUT_US)) DEV_ERR("%s: Error turning off audio engine.\n", __func__); } static struct hdmi_tx_ctrl *hdmi_tx_get_drvdata_from_panel_data( struct mdss_panel_data *mpd) { Loading Loading @@ -900,8 +859,7 @@ static ssize_t hdmi_tx_sysfs_wta_hpd(struct device *dev, hdmi_tx_config_5v(hdmi_ctrl, false); } else { hdmi_tx_hpd_off(hdmi_ctrl); hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0); hdmi_tx_send_cable_notification(hdmi_ctrl, 0); } break; Loading Loading @@ -1589,7 +1547,6 @@ static void hdmi_tx_hdcp_cb_work(struct work_struct *work) if (hdmi_tx_is_panel_on(hdmi_ctrl) && hdmi_tx_is_stream_shareable(hdmi_ctrl)) { rc = hdmi_tx_config_avmute(hdmi_ctrl, false); hdmi_tx_set_audio_switch_node(hdmi_ctrl, 1); } if (hdmi_ctrl->hdcp1_use_sw_keys && hdmi_ctrl->hdcp14_present) Loading @@ -1605,7 +1562,6 @@ static void hdmi_tx_hdcp_cb_work(struct work_struct *work) if (hdmi_tx_is_encryption_set(hdmi_ctrl) || !hdmi_tx_is_stream_shareable(hdmi_ctrl)) { hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0); rc = hdmi_tx_config_avmute(hdmi_ctrl, true); } Loading @@ -1631,7 +1587,6 @@ static void hdmi_tx_hdcp_cb_work(struct work_struct *work) if (hdmi_tx_is_panel_on(hdmi_ctrl)) { rc = hdmi_tx_config_avmute(hdmi_ctrl, false); hdmi_tx_set_audio_switch_node(hdmi_ctrl, 1); } break; case HDCP_STATE_AUTH_ENC_1X: Loading @@ -1641,9 +1596,7 @@ static void hdmi_tx_hdcp_cb_work(struct work_struct *work) if (hdmi_tx_is_panel_on(hdmi_ctrl) && hdmi_tx_is_stream_shareable(hdmi_ctrl)) { rc = hdmi_tx_config_avmute(hdmi_ctrl, false); hdmi_tx_set_audio_switch_node(hdmi_ctrl, 1); } else { hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0); rc = hdmi_tx_config_avmute(hdmi_ctrl, true); } break; Loading Loading @@ -2373,7 +2326,8 @@ static void hdmi_tx_hpd_int_work(struct work_struct *work) if (!hdmi_ctrl->hpd_initialized) { DEV_DBG("hpd not initialized\n"); goto end; mutex_unlock(&hdmi_ctrl->tx_lock); return; } DEV_DBG("%s: %s\n", __func__, Loading @@ -2386,16 +2340,11 @@ static void hdmi_tx_hpd_int_work(struct work_struct *work) pr_warn_ratelimited("%s: EDID read failed\n", __func__); hdmi_tx_update_deep_color(hdmi_ctrl); hdmi_tx_update_hdr_info(hdmi_ctrl); hdmi_tx_send_cable_notification(hdmi_ctrl, true); } else { hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0); hdmi_tx_wait_for_audio_engine(hdmi_ctrl); hdmi_tx_send_cable_notification(hdmi_ctrl, false); } end: mutex_unlock(&hdmi_ctrl->tx_lock); hdmi_tx_send_cable_notification(hdmi_ctrl, hdmi_ctrl->hpd_state); } /* hdmi_tx_hpd_int_work */ static int hdmi_tx_check_capability(struct hdmi_tx_ctrl *hdmi_ctrl) Loading Loading @@ -3239,7 +3188,6 @@ static int hdmi_tx_power_on(struct hdmi_tx_ctrl *hdmi_ctrl) if (hdmi_ctrl->panel.infoframe && !hdmi_tx_is_encryption_set(hdmi_ctrl) && hdmi_tx_is_stream_shareable(hdmi_ctrl)) { hdmi_tx_set_audio_switch_node(hdmi_ctrl, 1); hdmi_tx_config_avmute(hdmi_ctrl, false); } Loading Loading @@ -3845,20 +3793,6 @@ static int hdmi_tx_evt_handle_resume(struct hdmi_tx_ctrl *hdmi_ctrl) goto end; } if (hdmi_ctrl->sdev.state && !hdmi_tx_hw_is_cable_connected(hdmi_ctrl)) { u32 timeout; reinit_completion(&hdmi_ctrl->hpd_int_done); timeout = wait_for_completion_timeout( &hdmi_ctrl->hpd_int_done, HZ/10); if (!timeout && !hdmi_ctrl->hpd_state) { DEV_DBG("%s: cable removed during suspend\n", __func__); hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0); hdmi_tx_wait_for_audio_engine(hdmi_ctrl); hdmi_tx_send_cable_notification(hdmi_ctrl, 0); } } end: return rc; } Loading Loading @@ -3906,14 +3840,6 @@ static int hdmi_tx_evt_handle_panel_on(struct hdmi_tx_ctrl *hdmi_ctrl) hdmi_ctrl->timing_gen_on = true; if (hdmi_ctrl->panel_suspend) { DEV_DBG("%s: panel suspend has triggered\n", __func__); hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0); hdmi_tx_wait_for_audio_engine(hdmi_ctrl); hdmi_tx_send_cable_notification(hdmi_ctrl, 0); } return rc; } Loading Loading @@ -4003,6 +3929,55 @@ static int hdmi_tx_evt_handle_hdmi_ppm(struct hdmi_tx_ctrl *hdmi_ctrl) return hdmi_tx_update_ppm(hdmi_ctrl, ppm); } static int hdmi_tx_pre_evt_handle_panel_off(struct hdmi_tx_ctrl *hdmi_ctrl) { hdmi_tx_ack_state(hdmi_ctrl, false); return 0; } static int hdmi_tx_pre_evt_handle_update_fps(struct hdmi_tx_ctrl *hdmi_ctrl) { hdmi_ctrl->dynamic_fps = (u32) (unsigned long)hdmi_ctrl->evt_arg; queue_work(hdmi_ctrl->workq, &hdmi_ctrl->fps_work); return 0; } static int hdmi_tx_post_evt_handle_unblank(struct hdmi_tx_ctrl *hdmi_ctrl) { hdmi_tx_ack_state(hdmi_ctrl, true); return 0; } static int hdmi_tx_post_evt_handle_resume(struct hdmi_tx_ctrl *hdmi_ctrl) { if (!hdmi_ctrl->hpd_feature_on) return 0; if (!hdmi_tx_hw_is_cable_connected(hdmi_ctrl)) { u32 timeout; reinit_completion(&hdmi_ctrl->hpd_int_done); timeout = wait_for_completion_timeout( &hdmi_ctrl->hpd_int_done, HZ/10); if (!timeout) { pr_debug("cable removed during suspend\n"); hdmi_tx_send_cable_notification(hdmi_ctrl, 0); } } return 0; } static int hdmi_tx_post_evt_handle_panel_on(struct hdmi_tx_ctrl *hdmi_ctrl) { if (hdmi_ctrl->panel_suspend) { pr_debug("panel suspend has triggered\n"); hdmi_tx_send_cable_notification(hdmi_ctrl, 0); } return 0; } static int hdmi_tx_event_handler(struct mdss_panel_data *panel_data, int event, void *arg) { Loading @@ -4012,33 +3987,52 @@ static int hdmi_tx_event_handler(struct mdss_panel_data *panel_data, hdmi_tx_get_drvdata_from_panel_data(panel_data); if (!hdmi_ctrl) { DEV_ERR("%s: invalid input\n", __func__); rc = -EINVAL; goto end; } /* UPDATE FPS is called from atomic context */ if (event == MDSS_EVENT_PANEL_UPDATE_FPS) { hdmi_ctrl->dynamic_fps = (u32) (unsigned long)arg; queue_work(hdmi_ctrl->workq, &hdmi_ctrl->fps_work); return rc; pr_err("%s: invalid input\n", __func__); return -EINVAL; } mutex_lock(&hdmi_ctrl->tx_lock); hdmi_ctrl->evt_arg = arg; DEV_DBG("%s: event = %s suspend=%d, hpd_feature=%d\n", __func__, pr_debug("event = %s suspend=%d, hpd_feature=%d\n", mdss_panel_intf_event_to_string(event), hdmi_ctrl->panel_suspend, hdmi_ctrl->hpd_feature_on); /* event handlers prior to tx_lock */ handler = hdmi_ctrl->pre_evt_handler[event]; if (handler) { rc = handler(hdmi_ctrl); if (rc) { pr_err("pre handler failed: event = %s, rc = %d\n", mdss_panel_intf_event_to_string(event), rc); return rc; } } mutex_lock(&hdmi_ctrl->tx_lock); handler = hdmi_ctrl->evt_handler[event]; if (handler) if (handler) { rc = handler(hdmi_ctrl); if (rc) { pr_err("handler failed: event = %s, rc = %d\n", mdss_panel_intf_event_to_string(event), rc); mutex_unlock(&hdmi_ctrl->tx_lock); return rc; } } mutex_unlock(&hdmi_ctrl->tx_lock); end: /* event handlers post to tx_lock */ handler = hdmi_ctrl->post_evt_handler[event]; if (handler) { rc = handler(hdmi_ctrl); if (rc) pr_err("post handler failed: event = %s, rc = %d\n", mdss_panel_intf_event_to_string(event), rc); } return rc; } Loading Loading @@ -4692,7 +4686,6 @@ static int hdmi_tx_init_event_handler(struct hdmi_tx_ctrl *hdmi_ctrl) return -EINVAL; handler = hdmi_ctrl->evt_handler; handler[MDSS_EVENT_FB_REGISTERED] = hdmi_tx_evt_handle_register; handler[MDSS_EVENT_CHECK_PARAMS] = hdmi_tx_evt_handle_check_param; handler[MDSS_EVENT_RESUME] = hdmi_tx_evt_handle_resume; Loading @@ -4706,6 +4699,16 @@ static int hdmi_tx_init_event_handler(struct hdmi_tx_ctrl *hdmi_ctrl) handler[MDSS_EVENT_DEEP_COLOR] = hdmi_tx_evt_handle_deep_color; handler[MDSS_EVENT_UPDATE_PANEL_PPM] = hdmi_tx_evt_handle_hdmi_ppm; handler = hdmi_ctrl->pre_evt_handler; handler[MDSS_EVENT_PANEL_UPDATE_FPS] = hdmi_tx_pre_evt_handle_update_fps; handler[MDSS_EVENT_PANEL_OFF] = hdmi_tx_pre_evt_handle_panel_off; handler = hdmi_ctrl->post_evt_handler; handler[MDSS_EVENT_UNBLANK] = hdmi_tx_post_evt_handle_unblank; handler[MDSS_EVENT_RESUME] = hdmi_tx_post_evt_handle_resume; handler[MDSS_EVENT_PANEL_ON] = hdmi_tx_post_evt_handle_panel_on; return 0; } Loading
drivers/video/fbdev/msm/mdss_hdmi_tx.h +3 −1 Original line number Diff line number Diff line Loading @@ -98,7 +98,6 @@ struct hdmi_tx_ctrl { struct mutex tx_lock; struct list_head cable_notify_handlers; struct kobject *kobj; struct switch_dev sdev; struct workqueue_struct *workq; struct hdmi_util_ds_data ds_data; struct completion hpd_int_done; Loading Loading @@ -166,7 +165,10 @@ struct hdmi_tx_ctrl { char disp_switch_name[MAX_SWITCH_NAME_SIZE]; /* pre/post is done in the context without tx_lock */ hdmi_tx_evt_handler pre_evt_handler[MDSS_EVENT_MAX - 1]; hdmi_tx_evt_handler evt_handler[MDSS_EVENT_MAX - 1]; hdmi_tx_evt_handler post_evt_handler[MDSS_EVENT_MAX - 1]; }; #endif /* __MDSS_HDMI_TX_H__ */
include/linux/msm_ext_display.h +2 −3 Original line number Diff line number Diff line Loading @@ -91,7 +91,7 @@ enum msm_ext_disp_power_state { /** * struct msm_ext_disp_intf_ops - operations exposed to display interface * @hpd: updates external display interface state * @notify: updates audio framework with interface state * @notify: acknowledgment to power on or off */ struct msm_ext_disp_intf_ops { int (*hpd)(struct platform_device *pdev, Loading @@ -100,8 +100,7 @@ struct msm_ext_disp_intf_ops { u32 flags); int (*notify)(struct platform_device *pdev, enum msm_ext_disp_cable_state state); int (*ack)(struct platform_device *pdev, u32 ack); int (*ack)(struct platform_device *pdev, u32 ack); }; /** Loading