Loading drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c +135 −2 Original line number Diff line number Diff line Loading @@ -401,12 +401,111 @@ static const struct file_operations edid_vendor_name_fops = { .read = _sde_hdmi_edid_vendor_name_read, }; static u64 _sde_hdmi_clip_valid_pclk(struct drm_display_mode *mode, u64 pclk_in) { u32 pclk_delta, pclk; u64 pclk_clip = pclk_in; /* as per standard, 0.5% of deviation is allowed */ pclk = mode->clock * HDMI_KHZ_TO_HZ; pclk_delta = pclk * 5 / 1000; if (pclk_in < (pclk - pclk_delta)) pclk_clip = pclk - pclk_delta; else if (pclk_in > (pclk + pclk_delta)) pclk_clip = pclk + pclk_delta; if (pclk_in != pclk_clip) pr_warn("clip pclk from %lld to %lld\n", pclk_in, pclk_clip); return pclk_clip; } /** * _sde_hdmi_update_pll_delta() - Update the HDMI pixel clock as per input ppm * * @ppm: ppm is parts per million multiplied by 1000. * return: 0 on success, non-zero in case of failure. * * The input ppm will be clipped if it's more than or less than 5% of the TMDS * clock rate defined by HDMI spec. */ static int _sde_hdmi_update_pll_delta(struct sde_hdmi *display, s32 ppm) { struct hdmi *hdmi = display->ctrl.ctrl; struct drm_display_mode *current_mode = &display->mode; u64 cur_pclk, dst_pclk; u64 clip_pclk; int rc = 0; if (!hdmi->power_on || !display->connected) { SDE_ERROR("HDMI display is not ready\n"); return -EINVAL; } /* get current pclk */ cur_pclk = hdmi->pixclock; /* get desired pclk */ dst_pclk = cur_pclk * (1000000000 + ppm); do_div(dst_pclk, 1000000000); clip_pclk = _sde_hdmi_clip_valid_pclk(current_mode, dst_pclk); /* update pclk */ if (clip_pclk != cur_pclk) { SDE_DEBUG("PCLK changes from %llu to %llu when delta is %d\n", cur_pclk, clip_pclk, ppm); rc = clk_set_rate(hdmi->pwr_clks[0], clip_pclk); if (rc < 0) { SDE_ERROR("PLL update failed, reset clock rate\n"); return rc; } hdmi->pixclock = clip_pclk; } return rc; } static ssize_t _sde_hdmi_debugfs_pll_delta_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { struct sde_hdmi *display = file->private_data; char buf[10]; int ppm = 0; if (!display) return -ENODEV; if (count >= sizeof(buf)) return -EFAULT; if (copy_from_user(buf, user_buf, count)) return -EFAULT; buf[count] = 0; /* end of string */ if (kstrtoint(buf, 0, &ppm)) return -EFAULT; if (ppm) _sde_hdmi_update_pll_delta(display, ppm); return count; } static const struct file_operations pll_delta_fops = { .open = simple_open, .write = _sde_hdmi_debugfs_pll_delta_write, }; static int _sde_hdmi_debugfs_init(struct sde_hdmi *display) { int rc = 0; struct dentry *dir, *dump_file, *edid_modes; struct dentry *edid_vsdb_info, *edid_hdr_info, *edid_hfvsdb_info; struct dentry *edid_vcdb_info, *edid_vendor_name; struct dentry *edid_vcdb_info, *edid_vendor_name, *pll_file; dir = debugfs_create_dir(display->name, NULL); if (!dir) { Loading @@ -423,7 +522,19 @@ static int _sde_hdmi_debugfs_init(struct sde_hdmi *display) &dump_info_fops); if (IS_ERR_OR_NULL(dump_file)) { rc = PTR_ERR(dump_file); SDE_ERROR("[%s]debugfs create file failed, rc=%d\n", SDE_ERROR("[%s]debugfs create dump_info file failed, rc=%d\n", display->name, rc); goto error_remove_dir; } pll_file = debugfs_create_file("pll_delta", 0644, dir, display, &pll_delta_fops); if (IS_ERR_OR_NULL(pll_file)) { rc = PTR_ERR(pll_file); SDE_ERROR("[%s]debugfs create pll_delta file failed, rc=%d\n", display->name, rc); goto error_remove_dir; } Loading Loading @@ -1324,6 +1435,28 @@ int sde_hdmi_get_info(struct msm_display_info *info, return rc; } int sde_hdmi_set_property(struct drm_connector *connector, struct drm_connector_state *state, int property_index, uint64_t value, void *display) { int rc = 0; if (!connector || !display) { SDE_ERROR("connector=%pK or display=%pK is NULL\n", connector, display); return 0; } SDE_DEBUG("\n"); if (property_index == CONNECTOR_PROP_PLL_DELTA) rc = _sde_hdmi_update_pll_delta(display, value); return rc; } u32 sde_hdmi_get_num_of_displays(void) { u32 count = 0; Loading drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h +28 −0 Original line number Diff line number Diff line Loading @@ -80,6 +80,7 @@ struct sde_hdmi_ctrl { * @non_pluggable: If HDMI display is non pluggable * @num_of_modes: Number of modes supported by display if non pluggable. * @mode_list: Mode list if non pluggable. * @mode: Current display mode. * @connected: If HDMI display is connected. * @is_tpg_enabled: TPG state. * @hpd_work: HPD work structure. Loading @@ -103,6 +104,7 @@ struct sde_hdmi { bool non_pluggable; u32 num_of_modes; struct list_head mode_list; struct drm_display_mode mode; bool connected; bool is_tpg_enabled; Loading Loading @@ -269,6 +271,22 @@ int sde_hdmi_drm_deinit(struct sde_hdmi *display); int sde_hdmi_get_info(struct msm_display_info *info, void *display); /** * sde_hdmi_set_property() - set the connector properties * @connector: Handle to the connector. * @state: Handle to the connector state. * @property_index: property index. * @value: property value. * @display: Handle to the display. * * Return: error code. */ int sde_hdmi_set_property(struct drm_connector *connector, struct drm_connector_state *state, int property_index, uint64_t value, void *display); /** * sde_hdmi_bridge_init() - init sde hdmi bridge * @hdmi: Handle to the hdmi. Loading Loading @@ -453,5 +471,15 @@ static inline int sde_hdmi_get_info(struct msm_display_info *info, { return 0; } static inline int sde_hdmi_set_property(struct drm_connector *connector, struct drm_connector_state *state, int property_index, uint64_t value, void *display) { return 0; } #endif /*#else of CONFIG_DRM_SDE_HDMI*/ #endif /* _SDE_HDMI_H_ */ drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_audio.c +0 −2 Original line number Diff line number Diff line Loading @@ -30,8 +30,6 @@ #define HDMI_AUDIO_INFO_FRAME_PACKET_VERSION 0x1 #define HDMI_AUDIO_INFO_FRAME_PACKET_LENGTH 0x0A #define HDMI_KHZ_TO_HZ 1000 #define HDMI_MHZ_TO_HZ 1000000 #define HDMI_ACR_N_MULTIPLIER 128 #define DEFAULT_AUDIO_SAMPLE_RATE_HZ 48000 Loading drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c +11 −0 Original line number Diff line number Diff line Loading @@ -568,6 +568,15 @@ static void _sde_hdmi_bridge_set_spd_infoframe(struct hdmi *hdmi, hdmi_write(hdmi, REG_HDMI_GEN_PKT_CTRL, packet_control); } static inline void _sde_hdmi_save_mode(struct hdmi *hdmi, struct drm_display_mode *mode) { struct sde_connector *c_conn = to_sde_connector(hdmi->connector); struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display; drm_mode_copy(&display->mode, mode); } static void _sde_hdmi_bridge_mode_set(struct drm_bridge *bridge, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) Loading Loading @@ -640,6 +649,8 @@ static void _sde_hdmi_bridge_mode_set(struct drm_bridge *bridge, DRM_DEBUG("hdmi setup info frame\n"); } _sde_hdmi_bridge_setup_scrambler(hdmi, mode); _sde_hdmi_save_mode(hdmi, mode); } static const struct drm_bridge_funcs _sde_hdmi_bridge_funcs = { Loading drivers/gpu/drm/msm/msm_drv.h +1 −0 Original line number Diff line number Diff line Loading @@ -148,6 +148,7 @@ enum msm_mdp_conn_property { CONNECTOR_PROP_DST_Y, CONNECTOR_PROP_DST_W, CONNECTOR_PROP_DST_H, CONNECTOR_PROP_PLL_DELTA, /* enum/bitmask properties */ CONNECTOR_PROP_TOPOLOGY_NAME, Loading Loading
drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c +135 −2 Original line number Diff line number Diff line Loading @@ -401,12 +401,111 @@ static const struct file_operations edid_vendor_name_fops = { .read = _sde_hdmi_edid_vendor_name_read, }; static u64 _sde_hdmi_clip_valid_pclk(struct drm_display_mode *mode, u64 pclk_in) { u32 pclk_delta, pclk; u64 pclk_clip = pclk_in; /* as per standard, 0.5% of deviation is allowed */ pclk = mode->clock * HDMI_KHZ_TO_HZ; pclk_delta = pclk * 5 / 1000; if (pclk_in < (pclk - pclk_delta)) pclk_clip = pclk - pclk_delta; else if (pclk_in > (pclk + pclk_delta)) pclk_clip = pclk + pclk_delta; if (pclk_in != pclk_clip) pr_warn("clip pclk from %lld to %lld\n", pclk_in, pclk_clip); return pclk_clip; } /** * _sde_hdmi_update_pll_delta() - Update the HDMI pixel clock as per input ppm * * @ppm: ppm is parts per million multiplied by 1000. * return: 0 on success, non-zero in case of failure. * * The input ppm will be clipped if it's more than or less than 5% of the TMDS * clock rate defined by HDMI spec. */ static int _sde_hdmi_update_pll_delta(struct sde_hdmi *display, s32 ppm) { struct hdmi *hdmi = display->ctrl.ctrl; struct drm_display_mode *current_mode = &display->mode; u64 cur_pclk, dst_pclk; u64 clip_pclk; int rc = 0; if (!hdmi->power_on || !display->connected) { SDE_ERROR("HDMI display is not ready\n"); return -EINVAL; } /* get current pclk */ cur_pclk = hdmi->pixclock; /* get desired pclk */ dst_pclk = cur_pclk * (1000000000 + ppm); do_div(dst_pclk, 1000000000); clip_pclk = _sde_hdmi_clip_valid_pclk(current_mode, dst_pclk); /* update pclk */ if (clip_pclk != cur_pclk) { SDE_DEBUG("PCLK changes from %llu to %llu when delta is %d\n", cur_pclk, clip_pclk, ppm); rc = clk_set_rate(hdmi->pwr_clks[0], clip_pclk); if (rc < 0) { SDE_ERROR("PLL update failed, reset clock rate\n"); return rc; } hdmi->pixclock = clip_pclk; } return rc; } static ssize_t _sde_hdmi_debugfs_pll_delta_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { struct sde_hdmi *display = file->private_data; char buf[10]; int ppm = 0; if (!display) return -ENODEV; if (count >= sizeof(buf)) return -EFAULT; if (copy_from_user(buf, user_buf, count)) return -EFAULT; buf[count] = 0; /* end of string */ if (kstrtoint(buf, 0, &ppm)) return -EFAULT; if (ppm) _sde_hdmi_update_pll_delta(display, ppm); return count; } static const struct file_operations pll_delta_fops = { .open = simple_open, .write = _sde_hdmi_debugfs_pll_delta_write, }; static int _sde_hdmi_debugfs_init(struct sde_hdmi *display) { int rc = 0; struct dentry *dir, *dump_file, *edid_modes; struct dentry *edid_vsdb_info, *edid_hdr_info, *edid_hfvsdb_info; struct dentry *edid_vcdb_info, *edid_vendor_name; struct dentry *edid_vcdb_info, *edid_vendor_name, *pll_file; dir = debugfs_create_dir(display->name, NULL); if (!dir) { Loading @@ -423,7 +522,19 @@ static int _sde_hdmi_debugfs_init(struct sde_hdmi *display) &dump_info_fops); if (IS_ERR_OR_NULL(dump_file)) { rc = PTR_ERR(dump_file); SDE_ERROR("[%s]debugfs create file failed, rc=%d\n", SDE_ERROR("[%s]debugfs create dump_info file failed, rc=%d\n", display->name, rc); goto error_remove_dir; } pll_file = debugfs_create_file("pll_delta", 0644, dir, display, &pll_delta_fops); if (IS_ERR_OR_NULL(pll_file)) { rc = PTR_ERR(pll_file); SDE_ERROR("[%s]debugfs create pll_delta file failed, rc=%d\n", display->name, rc); goto error_remove_dir; } Loading Loading @@ -1324,6 +1435,28 @@ int sde_hdmi_get_info(struct msm_display_info *info, return rc; } int sde_hdmi_set_property(struct drm_connector *connector, struct drm_connector_state *state, int property_index, uint64_t value, void *display) { int rc = 0; if (!connector || !display) { SDE_ERROR("connector=%pK or display=%pK is NULL\n", connector, display); return 0; } SDE_DEBUG("\n"); if (property_index == CONNECTOR_PROP_PLL_DELTA) rc = _sde_hdmi_update_pll_delta(display, value); return rc; } u32 sde_hdmi_get_num_of_displays(void) { u32 count = 0; Loading
drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h +28 −0 Original line number Diff line number Diff line Loading @@ -80,6 +80,7 @@ struct sde_hdmi_ctrl { * @non_pluggable: If HDMI display is non pluggable * @num_of_modes: Number of modes supported by display if non pluggable. * @mode_list: Mode list if non pluggable. * @mode: Current display mode. * @connected: If HDMI display is connected. * @is_tpg_enabled: TPG state. * @hpd_work: HPD work structure. Loading @@ -103,6 +104,7 @@ struct sde_hdmi { bool non_pluggable; u32 num_of_modes; struct list_head mode_list; struct drm_display_mode mode; bool connected; bool is_tpg_enabled; Loading Loading @@ -269,6 +271,22 @@ int sde_hdmi_drm_deinit(struct sde_hdmi *display); int sde_hdmi_get_info(struct msm_display_info *info, void *display); /** * sde_hdmi_set_property() - set the connector properties * @connector: Handle to the connector. * @state: Handle to the connector state. * @property_index: property index. * @value: property value. * @display: Handle to the display. * * Return: error code. */ int sde_hdmi_set_property(struct drm_connector *connector, struct drm_connector_state *state, int property_index, uint64_t value, void *display); /** * sde_hdmi_bridge_init() - init sde hdmi bridge * @hdmi: Handle to the hdmi. Loading Loading @@ -453,5 +471,15 @@ static inline int sde_hdmi_get_info(struct msm_display_info *info, { return 0; } static inline int sde_hdmi_set_property(struct drm_connector *connector, struct drm_connector_state *state, int property_index, uint64_t value, void *display) { return 0; } #endif /*#else of CONFIG_DRM_SDE_HDMI*/ #endif /* _SDE_HDMI_H_ */
drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_audio.c +0 −2 Original line number Diff line number Diff line Loading @@ -30,8 +30,6 @@ #define HDMI_AUDIO_INFO_FRAME_PACKET_VERSION 0x1 #define HDMI_AUDIO_INFO_FRAME_PACKET_LENGTH 0x0A #define HDMI_KHZ_TO_HZ 1000 #define HDMI_MHZ_TO_HZ 1000000 #define HDMI_ACR_N_MULTIPLIER 128 #define DEFAULT_AUDIO_SAMPLE_RATE_HZ 48000 Loading
drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c +11 −0 Original line number Diff line number Diff line Loading @@ -568,6 +568,15 @@ static void _sde_hdmi_bridge_set_spd_infoframe(struct hdmi *hdmi, hdmi_write(hdmi, REG_HDMI_GEN_PKT_CTRL, packet_control); } static inline void _sde_hdmi_save_mode(struct hdmi *hdmi, struct drm_display_mode *mode) { struct sde_connector *c_conn = to_sde_connector(hdmi->connector); struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display; drm_mode_copy(&display->mode, mode); } static void _sde_hdmi_bridge_mode_set(struct drm_bridge *bridge, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) Loading Loading @@ -640,6 +649,8 @@ static void _sde_hdmi_bridge_mode_set(struct drm_bridge *bridge, DRM_DEBUG("hdmi setup info frame\n"); } _sde_hdmi_bridge_setup_scrambler(hdmi, mode); _sde_hdmi_save_mode(hdmi, mode); } static const struct drm_bridge_funcs _sde_hdmi_bridge_funcs = { Loading
drivers/gpu/drm/msm/msm_drv.h +1 −0 Original line number Diff line number Diff line Loading @@ -148,6 +148,7 @@ enum msm_mdp_conn_property { CONNECTOR_PROP_DST_Y, CONNECTOR_PROP_DST_W, CONNECTOR_PROP_DST_H, CONNECTOR_PROP_PLL_DELTA, /* enum/bitmask properties */ CONNECTOR_PROP_TOPOLOGY_NAME, Loading