Loading drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c +9 −6 Original line number Diff line number Diff line Loading @@ -556,13 +556,13 @@ static const struct file_operations sde_hdmi_hdcp_state_fops = { .read = _sde_hdmi_hdcp_state_read, }; static u64 _sde_hdmi_clip_valid_pclk(struct drm_display_mode *mode, u64 pclk_in) static u64 _sde_hdmi_clip_valid_pclk(struct hdmi *hdmi, 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 = hdmi->pixclock; pclk_delta = pclk * 5 / 1000; if (pclk_in < (pclk - pclk_delta)) Loading Loading @@ -700,7 +700,6 @@ static void sde_hdmi_tx_hdcp_cb_work(struct work_struct *work) 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; Loading @@ -725,7 +724,7 @@ static int _sde_hdmi_update_pll_delta(struct sde_hdmi *display, s32 ppm) dst_pclk = cur_pclk * (1000000000 + ppm); do_div(dst_pclk, 1000000000); clip_pclk = _sde_hdmi_clip_valid_pclk(current_mode, dst_pclk); clip_pclk = _sde_hdmi_clip_valid_pclk(hdmi, dst_pclk); /* update pclk */ if (clip_pclk != cur_pclk) { Loading Loading @@ -2126,9 +2125,13 @@ static int sde_hdmi_tx_check_capability(struct sde_hdmi *sde_hdmi) } } SDE_DEBUG("%s: Features <HDMI:%s, HDCP:%s>\n", __func__, if (sde_hdmi->hdmi_tx_major_version >= HDMI_TX_VERSION_4) sde_hdmi->dc_feature_supported = true; SDE_DEBUG("%s: Features <HDMI:%s, HDCP:%s, Deep Color:%s>\n", __func__, hdmi_disabled ? "OFF" : "ON", hdcp_disabled ? "OFF" : "ON"); hdcp_disabled ? "OFF" : "ON", sde_hdmi->dc_feature_supported ? "ON" : "OFF"); if (hdmi_disabled) { DEV_ERR("%s: HDMI disabled\n", __func__); Loading drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h +9 −0 Original line number Diff line number Diff line Loading @@ -33,6 +33,9 @@ #include "sde_hdmi_util.h" #include "sde_hdcp.h" #ifndef MIN #define MIN(x, y) (((x) < (y)) ? (x) : (y)) #endif #ifdef HDMI_DEBUG_ENABLE #define SDE_HDMI_DEBUG(fmt, args...) SDE_ERROR(fmt, ##args) #else Loading Loading @@ -110,6 +113,8 @@ enum hdmi_tx_feature_type { * @client_notify_pending: If there is client notification pending. * @irq_domain: IRQ domain structure. * @pll_update_enable: if it's allowed to update HDMI PLL ppm. * @dc_enable: If deep color is enabled. Only DC_30 so far. * @dc_feature_supported: If deep color feature is supported. * @notifier: CEC notifider to convey physical address information. * @root: Debug fs root entry. */ Loading Loading @@ -161,6 +166,8 @@ struct sde_hdmi { struct irq_domain *irq_domain; struct cec_notifier *notifier; bool pll_update_enable; bool dc_enable; bool dc_feature_supported; struct delayed_work hdcp_cb_work; struct dss_io_data io[HDMI_TX_MAX_IO]; Loading Loading @@ -188,6 +195,8 @@ enum hdmi_tx_scdc_access_type { #define HDMI_KHZ_TO_HZ 1000 #define HDMI_MHZ_TO_HZ 1000000 #define HDMI_YUV420_24BPP_PCLK_TMDS_CH_RATE_RATIO 2 #define HDMI_RGB_24BPP_PCLK_TMDS_CH_RATE_RATIO 1 /* Maximum pixel clock rates for hdmi tx */ #define HDMI_DEFAULT_MAX_PCLK_RATE 148500 Loading drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c +85 −2 Original line number Diff line number Diff line Loading @@ -345,7 +345,9 @@ static int _sde_hdmi_bridge_setup_scrambler(struct hdmi *hdmi, return 0; } if (mode->clock > HDMI_TX_SCRAMBLER_THRESHOLD_RATE_KHZ) { /* use actual clock instead of mode clock */ if (hdmi->pixclock > HDMI_TX_SCRAMBLER_THRESHOLD_RATE_KHZ * HDMI_KHZ_TO_HZ) { scrambler_on = true; tmds_clock_ratio = 1; } else { Loading Loading @@ -402,6 +404,38 @@ static int _sde_hdmi_bridge_setup_scrambler(struct hdmi *hdmi, return rc; } static void _sde_hdmi_bridge_setup_deep_color(struct hdmi *hdmi) { struct drm_connector *connector = hdmi->connector; struct sde_connector *c_conn = to_sde_connector(connector); struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display; u32 hdmi_ctrl_reg, vbi_pkt_reg; SDE_DEBUG("Deep Color: %s\n", display->dc_enable ? "On" : "Off"); if (display->dc_enable) { hdmi_ctrl_reg = hdmi_read(hdmi, REG_HDMI_CTRL); /* GC CD override */ hdmi_ctrl_reg |= BIT(27); /* enable deep color for RGB888/YUV444/YUV420 30 bits */ hdmi_ctrl_reg |= BIT(24); hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl_reg); /* Enable GC_CONT and GC_SEND in General Control Packet * (GCP) register so that deep color data is * transmitted to the sink on every frame, allowing * the sink to decode the data correctly. * * GC_CONT: 0x1 - Send GCP on every frame * GC_SEND: 0x1 - Enable GCP Transmission */ vbi_pkt_reg = hdmi_read(hdmi, REG_HDMI_VBI_PKT_CTRL); vbi_pkt_reg |= BIT(5) | BIT(4); hdmi_write(hdmi, REG_HDMI_VBI_PKT_CTRL, vbi_pkt_reg); } } static void _sde_hdmi_bridge_pre_enable(struct drm_bridge *bridge) { struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge); Loading Loading @@ -660,18 +694,52 @@ static inline void _sde_hdmi_save_mode(struct hdmi *hdmi, drm_mode_copy(&display->mode, mode); } static u32 _sde_hdmi_choose_best_format(struct hdmi *hdmi, struct drm_display_mode *mode) { /* * choose priority: * 1. DC + RGB * 2. DC + YUV * 3. RGB * 4. YUV */ int dc_format; struct drm_connector *connector = hdmi->connector; dc_format = sde_hdmi_sink_dc_support(connector, mode); if (dc_format & MSM_MODE_FLAG_RGB444_DC_ENABLE) return (MSM_MODE_FLAG_COLOR_FORMAT_RGB444 | MSM_MODE_FLAG_RGB444_DC_ENABLE); return MSM_MODE_FLAG_COLOR_FORMAT_RGB444; } static void _sde_hdmi_bridge_mode_set(struct drm_bridge *bridge, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge); struct hdmi *hdmi = sde_hdmi_bridge->hdmi; struct drm_connector *connector = hdmi->connector; struct sde_connector *c_conn = to_sde_connector(connector); struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display; int hstart, hend, vstart, vend; uint32_t frame_ctrl; mode = adjusted_mode; hdmi->pixclock = mode->clock * 1000; display->dc_enable = mode->private_flags & (MSM_MODE_FLAG_RGB444_DC_ENABLE | MSM_MODE_FLAG_YUV420_DC_ENABLE); /* compute pixclock as per color format and bit depth */ hdmi->pixclock = sde_hdmi_calc_pixclk( mode->clock * HDMI_KHZ_TO_HZ, mode->private_flags, display->dc_enable); SDE_DEBUG("Actual PCLK: %lu, Mode PCLK: %d\n", hdmi->pixclock, mode->clock); hstart = mode->htotal - mode->hsync_start; hend = mode->htotal - mode->hsync_start + mode->hdisplay; Loading Loading @@ -734,6 +802,20 @@ static void _sde_hdmi_bridge_mode_set(struct drm_bridge *bridge, _sde_hdmi_save_mode(hdmi, mode); _sde_hdmi_bridge_setup_scrambler(hdmi, mode); _sde_hdmi_bridge_setup_deep_color(hdmi); } static bool _sde_hdmi_bridge_mode_fixup(struct drm_bridge *bridge, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge); struct hdmi *hdmi = sde_hdmi_bridge->hdmi; adjusted_mode->private_flags |= _sde_hdmi_choose_best_format(hdmi, adjusted_mode); return true; } static const struct drm_bridge_funcs _sde_hdmi_bridge_funcs = { Loading @@ -742,6 +824,7 @@ static const struct drm_bridge_funcs _sde_hdmi_bridge_funcs = { .disable = _sde_hdmi_bridge_disable, .post_disable = _sde_hdmi_bridge_post_disable, .mode_set = _sde_hdmi_bridge_mode_set, .mode_fixup = _sde_hdmi_bridge_mode_fixup, }; Loading drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.c +73 −0 Original line number Diff line number Diff line Loading @@ -825,3 +825,76 @@ int sde_hdmi_hdcp2p2_read_rxstatus(void *hdmi_display) } return rc; } unsigned long sde_hdmi_calc_pixclk(unsigned long pixel_freq, u32 out_format, bool dc_enable) { u32 rate_ratio = HDMI_RGB_24BPP_PCLK_TMDS_CH_RATE_RATIO; if (out_format & MSM_MODE_FLAG_COLOR_FORMAT_YCBCR420) rate_ratio = HDMI_YUV420_24BPP_PCLK_TMDS_CH_RATE_RATIO; pixel_freq /= rate_ratio; if (dc_enable) pixel_freq += pixel_freq >> 2; return pixel_freq; } bool sde_hdmi_validate_pixclk(struct drm_connector *connector, unsigned long pclk) { struct sde_connector *c_conn = to_sde_connector(connector); struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display; unsigned long max_pclk = display->max_pclk_khz * HDMI_KHZ_TO_HZ; if (connector->max_tmds_char) max_pclk = MIN(max_pclk, connector->max_tmds_char * HDMI_MHZ_TO_HZ); else if (connector->max_tmds_clock) max_pclk = MIN(max_pclk, connector->max_tmds_clock * HDMI_MHZ_TO_HZ); SDE_DEBUG("MAX PCLK = %ld, PCLK = %ld\n", max_pclk, pclk); return pclk < max_pclk; } static bool sde_hdmi_check_dc_clock(struct drm_connector *connector, struct drm_display_mode *mode, u32 format) { struct sde_connector *c_conn = to_sde_connector(connector); struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display; u32 tmds_clk_with_dc = sde_hdmi_calc_pixclk( mode->clock * HDMI_KHZ_TO_HZ, format, true); return (display->dc_feature_supported && sde_hdmi_validate_pixclk(connector, tmds_clk_with_dc)); } int sde_hdmi_sink_dc_support(struct drm_connector *connector, struct drm_display_mode *mode) { int dc_format = 0; if ((mode->flags & DRM_MODE_FLAG_SUPPORTS_YUV) && (connector->display_info.edid_hdmi_dc_modes & DRM_EDID_YCBCR420_DC_30)) if (sde_hdmi_check_dc_clock(connector, mode, MSM_MODE_FLAG_COLOR_FORMAT_YCBCR420)) dc_format |= MSM_MODE_FLAG_YUV420_DC_ENABLE; if ((mode->flags & DRM_MODE_FLAG_SUPPORTS_RGB) && (connector->display_info.edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_30)) if (sde_hdmi_check_dc_clock(connector, mode, MSM_MODE_FLAG_COLOR_FORMAT_RGB444)) dc_format |= MSM_MODE_FLAG_RGB444_DC_ENABLE; return dc_format; } drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h +6 −0 Original line number Diff line number Diff line Loading @@ -164,4 +164,10 @@ int sde_hdmi_hdcp2p2_read_rxstatus(void *hdmi_display); void sde_hdmi_ddc_config(void *hdmi_display); int sde_hdmi_ddc_hdcp2p2_isr(void *hdmi_display); void sde_hdmi_dump_regs(void *hdmi_display); unsigned long sde_hdmi_calc_pixclk(unsigned long pixel_freq, u32 out_format, bool dc_enable); bool sde_hdmi_validate_pixclk(struct drm_connector *connector, unsigned long pclk); int sde_hdmi_sink_dc_support(struct drm_connector *connector, struct drm_display_mode *mode); #endif /* _SDE_HDMI_UTIL_H_ */ Loading
drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c +9 −6 Original line number Diff line number Diff line Loading @@ -556,13 +556,13 @@ static const struct file_operations sde_hdmi_hdcp_state_fops = { .read = _sde_hdmi_hdcp_state_read, }; static u64 _sde_hdmi_clip_valid_pclk(struct drm_display_mode *mode, u64 pclk_in) static u64 _sde_hdmi_clip_valid_pclk(struct hdmi *hdmi, 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 = hdmi->pixclock; pclk_delta = pclk * 5 / 1000; if (pclk_in < (pclk - pclk_delta)) Loading Loading @@ -700,7 +700,6 @@ static void sde_hdmi_tx_hdcp_cb_work(struct work_struct *work) 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; Loading @@ -725,7 +724,7 @@ static int _sde_hdmi_update_pll_delta(struct sde_hdmi *display, s32 ppm) dst_pclk = cur_pclk * (1000000000 + ppm); do_div(dst_pclk, 1000000000); clip_pclk = _sde_hdmi_clip_valid_pclk(current_mode, dst_pclk); clip_pclk = _sde_hdmi_clip_valid_pclk(hdmi, dst_pclk); /* update pclk */ if (clip_pclk != cur_pclk) { Loading Loading @@ -2126,9 +2125,13 @@ static int sde_hdmi_tx_check_capability(struct sde_hdmi *sde_hdmi) } } SDE_DEBUG("%s: Features <HDMI:%s, HDCP:%s>\n", __func__, if (sde_hdmi->hdmi_tx_major_version >= HDMI_TX_VERSION_4) sde_hdmi->dc_feature_supported = true; SDE_DEBUG("%s: Features <HDMI:%s, HDCP:%s, Deep Color:%s>\n", __func__, hdmi_disabled ? "OFF" : "ON", hdcp_disabled ? "OFF" : "ON"); hdcp_disabled ? "OFF" : "ON", sde_hdmi->dc_feature_supported ? "ON" : "OFF"); if (hdmi_disabled) { DEV_ERR("%s: HDMI disabled\n", __func__); Loading
drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h +9 −0 Original line number Diff line number Diff line Loading @@ -33,6 +33,9 @@ #include "sde_hdmi_util.h" #include "sde_hdcp.h" #ifndef MIN #define MIN(x, y) (((x) < (y)) ? (x) : (y)) #endif #ifdef HDMI_DEBUG_ENABLE #define SDE_HDMI_DEBUG(fmt, args...) SDE_ERROR(fmt, ##args) #else Loading Loading @@ -110,6 +113,8 @@ enum hdmi_tx_feature_type { * @client_notify_pending: If there is client notification pending. * @irq_domain: IRQ domain structure. * @pll_update_enable: if it's allowed to update HDMI PLL ppm. * @dc_enable: If deep color is enabled. Only DC_30 so far. * @dc_feature_supported: If deep color feature is supported. * @notifier: CEC notifider to convey physical address information. * @root: Debug fs root entry. */ Loading Loading @@ -161,6 +166,8 @@ struct sde_hdmi { struct irq_domain *irq_domain; struct cec_notifier *notifier; bool pll_update_enable; bool dc_enable; bool dc_feature_supported; struct delayed_work hdcp_cb_work; struct dss_io_data io[HDMI_TX_MAX_IO]; Loading Loading @@ -188,6 +195,8 @@ enum hdmi_tx_scdc_access_type { #define HDMI_KHZ_TO_HZ 1000 #define HDMI_MHZ_TO_HZ 1000000 #define HDMI_YUV420_24BPP_PCLK_TMDS_CH_RATE_RATIO 2 #define HDMI_RGB_24BPP_PCLK_TMDS_CH_RATE_RATIO 1 /* Maximum pixel clock rates for hdmi tx */ #define HDMI_DEFAULT_MAX_PCLK_RATE 148500 Loading
drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c +85 −2 Original line number Diff line number Diff line Loading @@ -345,7 +345,9 @@ static int _sde_hdmi_bridge_setup_scrambler(struct hdmi *hdmi, return 0; } if (mode->clock > HDMI_TX_SCRAMBLER_THRESHOLD_RATE_KHZ) { /* use actual clock instead of mode clock */ if (hdmi->pixclock > HDMI_TX_SCRAMBLER_THRESHOLD_RATE_KHZ * HDMI_KHZ_TO_HZ) { scrambler_on = true; tmds_clock_ratio = 1; } else { Loading Loading @@ -402,6 +404,38 @@ static int _sde_hdmi_bridge_setup_scrambler(struct hdmi *hdmi, return rc; } static void _sde_hdmi_bridge_setup_deep_color(struct hdmi *hdmi) { struct drm_connector *connector = hdmi->connector; struct sde_connector *c_conn = to_sde_connector(connector); struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display; u32 hdmi_ctrl_reg, vbi_pkt_reg; SDE_DEBUG("Deep Color: %s\n", display->dc_enable ? "On" : "Off"); if (display->dc_enable) { hdmi_ctrl_reg = hdmi_read(hdmi, REG_HDMI_CTRL); /* GC CD override */ hdmi_ctrl_reg |= BIT(27); /* enable deep color for RGB888/YUV444/YUV420 30 bits */ hdmi_ctrl_reg |= BIT(24); hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl_reg); /* Enable GC_CONT and GC_SEND in General Control Packet * (GCP) register so that deep color data is * transmitted to the sink on every frame, allowing * the sink to decode the data correctly. * * GC_CONT: 0x1 - Send GCP on every frame * GC_SEND: 0x1 - Enable GCP Transmission */ vbi_pkt_reg = hdmi_read(hdmi, REG_HDMI_VBI_PKT_CTRL); vbi_pkt_reg |= BIT(5) | BIT(4); hdmi_write(hdmi, REG_HDMI_VBI_PKT_CTRL, vbi_pkt_reg); } } static void _sde_hdmi_bridge_pre_enable(struct drm_bridge *bridge) { struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge); Loading Loading @@ -660,18 +694,52 @@ static inline void _sde_hdmi_save_mode(struct hdmi *hdmi, drm_mode_copy(&display->mode, mode); } static u32 _sde_hdmi_choose_best_format(struct hdmi *hdmi, struct drm_display_mode *mode) { /* * choose priority: * 1. DC + RGB * 2. DC + YUV * 3. RGB * 4. YUV */ int dc_format; struct drm_connector *connector = hdmi->connector; dc_format = sde_hdmi_sink_dc_support(connector, mode); if (dc_format & MSM_MODE_FLAG_RGB444_DC_ENABLE) return (MSM_MODE_FLAG_COLOR_FORMAT_RGB444 | MSM_MODE_FLAG_RGB444_DC_ENABLE); return MSM_MODE_FLAG_COLOR_FORMAT_RGB444; } static void _sde_hdmi_bridge_mode_set(struct drm_bridge *bridge, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge); struct hdmi *hdmi = sde_hdmi_bridge->hdmi; struct drm_connector *connector = hdmi->connector; struct sde_connector *c_conn = to_sde_connector(connector); struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display; int hstart, hend, vstart, vend; uint32_t frame_ctrl; mode = adjusted_mode; hdmi->pixclock = mode->clock * 1000; display->dc_enable = mode->private_flags & (MSM_MODE_FLAG_RGB444_DC_ENABLE | MSM_MODE_FLAG_YUV420_DC_ENABLE); /* compute pixclock as per color format and bit depth */ hdmi->pixclock = sde_hdmi_calc_pixclk( mode->clock * HDMI_KHZ_TO_HZ, mode->private_flags, display->dc_enable); SDE_DEBUG("Actual PCLK: %lu, Mode PCLK: %d\n", hdmi->pixclock, mode->clock); hstart = mode->htotal - mode->hsync_start; hend = mode->htotal - mode->hsync_start + mode->hdisplay; Loading Loading @@ -734,6 +802,20 @@ static void _sde_hdmi_bridge_mode_set(struct drm_bridge *bridge, _sde_hdmi_save_mode(hdmi, mode); _sde_hdmi_bridge_setup_scrambler(hdmi, mode); _sde_hdmi_bridge_setup_deep_color(hdmi); } static bool _sde_hdmi_bridge_mode_fixup(struct drm_bridge *bridge, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge); struct hdmi *hdmi = sde_hdmi_bridge->hdmi; adjusted_mode->private_flags |= _sde_hdmi_choose_best_format(hdmi, adjusted_mode); return true; } static const struct drm_bridge_funcs _sde_hdmi_bridge_funcs = { Loading @@ -742,6 +824,7 @@ static const struct drm_bridge_funcs _sde_hdmi_bridge_funcs = { .disable = _sde_hdmi_bridge_disable, .post_disable = _sde_hdmi_bridge_post_disable, .mode_set = _sde_hdmi_bridge_mode_set, .mode_fixup = _sde_hdmi_bridge_mode_fixup, }; Loading
drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.c +73 −0 Original line number Diff line number Diff line Loading @@ -825,3 +825,76 @@ int sde_hdmi_hdcp2p2_read_rxstatus(void *hdmi_display) } return rc; } unsigned long sde_hdmi_calc_pixclk(unsigned long pixel_freq, u32 out_format, bool dc_enable) { u32 rate_ratio = HDMI_RGB_24BPP_PCLK_TMDS_CH_RATE_RATIO; if (out_format & MSM_MODE_FLAG_COLOR_FORMAT_YCBCR420) rate_ratio = HDMI_YUV420_24BPP_PCLK_TMDS_CH_RATE_RATIO; pixel_freq /= rate_ratio; if (dc_enable) pixel_freq += pixel_freq >> 2; return pixel_freq; } bool sde_hdmi_validate_pixclk(struct drm_connector *connector, unsigned long pclk) { struct sde_connector *c_conn = to_sde_connector(connector); struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display; unsigned long max_pclk = display->max_pclk_khz * HDMI_KHZ_TO_HZ; if (connector->max_tmds_char) max_pclk = MIN(max_pclk, connector->max_tmds_char * HDMI_MHZ_TO_HZ); else if (connector->max_tmds_clock) max_pclk = MIN(max_pclk, connector->max_tmds_clock * HDMI_MHZ_TO_HZ); SDE_DEBUG("MAX PCLK = %ld, PCLK = %ld\n", max_pclk, pclk); return pclk < max_pclk; } static bool sde_hdmi_check_dc_clock(struct drm_connector *connector, struct drm_display_mode *mode, u32 format) { struct sde_connector *c_conn = to_sde_connector(connector); struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display; u32 tmds_clk_with_dc = sde_hdmi_calc_pixclk( mode->clock * HDMI_KHZ_TO_HZ, format, true); return (display->dc_feature_supported && sde_hdmi_validate_pixclk(connector, tmds_clk_with_dc)); } int sde_hdmi_sink_dc_support(struct drm_connector *connector, struct drm_display_mode *mode) { int dc_format = 0; if ((mode->flags & DRM_MODE_FLAG_SUPPORTS_YUV) && (connector->display_info.edid_hdmi_dc_modes & DRM_EDID_YCBCR420_DC_30)) if (sde_hdmi_check_dc_clock(connector, mode, MSM_MODE_FLAG_COLOR_FORMAT_YCBCR420)) dc_format |= MSM_MODE_FLAG_YUV420_DC_ENABLE; if ((mode->flags & DRM_MODE_FLAG_SUPPORTS_RGB) && (connector->display_info.edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_30)) if (sde_hdmi_check_dc_clock(connector, mode, MSM_MODE_FLAG_COLOR_FORMAT_RGB444)) dc_format |= MSM_MODE_FLAG_RGB444_DC_ENABLE; return dc_format; }
drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h +6 −0 Original line number Diff line number Diff line Loading @@ -164,4 +164,10 @@ int sde_hdmi_hdcp2p2_read_rxstatus(void *hdmi_display); void sde_hdmi_ddc_config(void *hdmi_display); int sde_hdmi_ddc_hdcp2p2_isr(void *hdmi_display); void sde_hdmi_dump_regs(void *hdmi_display); unsigned long sde_hdmi_calc_pixclk(unsigned long pixel_freq, u32 out_format, bool dc_enable); bool sde_hdmi_validate_pixclk(struct drm_connector *connector, unsigned long pclk); int sde_hdmi_sink_dc_support(struct drm_connector *connector, struct drm_display_mode *mode); #endif /* _SDE_HDMI_UTIL_H_ */