aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShashank Sharma <shashank.sharma@intel.com>2017-03-13 07:24:02 -0400
committerJani Nikula <jani.nikula@intel.com>2017-03-21 04:15:56 -0400
commit62c58af32c935a98a1e8d8ceb39a3a47b36fbbcd (patch)
treeea1dca1ec86bdb3f213f69f9899dd05e51cd2762
parentafa1c763653e0fd68f2d1e3dca869c9453d8ef06 (diff)
drm/edid: detect SCDC support in HF-VSDB
This patch does following: - Adds a new structure (drm_hdmi_info) in drm_display_info. This structure will be used to save and indicate if sink supports advanced HDMI 2.0 features - Adds another structure drm_scdc within drm_hdmi_info, to reflect scdc support and capabilities in connected HDMI 2.0 sink. - Checks the HF-VSDB block for presence of SCDC, and marks it in scdc structure - If SCDC is present, checks if sink is capable of generating SCDC read request, and marks it in scdc structure. V2: Addressed review comments Thierry: - Fix typos in commit message and make abbreviation consistent across the commit message. - Change structure object name from hdmi_info -> hdmi - Fix typos and abbreviations in description of structure drm_hdmi_info end the description with a full stop. - Create a structure drm_scdc, and keep all information related to SCDC register set (supported, read request supported) etc in it. Ville: - Change rr -> read_request - Call drm_detect_scrambling function drm_parse_hf_vsdb so that all of HF-VSDB parsing can be kept in same function, in incremental patches. V3: Rebase. V4: Rebase. V5: Rebase. V6: Addressed review comments from Ville - Add clock rate calculations for 1/10 and 1/40 ratios - Remove leftovers from old patchset V7: Added R-B from Jose. V8: Rebase. V9: Rebase. V10: Rebase. Signed-off-by: Shashank Sharma <shashank.sharma@intel.com> Reviewed-by: Thierry Reding <treding@nvidia.com> Reviewed-by: Jose Abreu <joabreu@synopsys.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: http://patchwork.freedesktop.org/patch/msgid/1489404244-16608-5-git-send-email-shashank.sharma@intel.com
-rw-r--r--drivers/gpu/drm/drm_edid.c33
-rw-r--r--drivers/gpu/drm/drm_scdc_helper.c121
-rw-r--r--include/drm/drm_connector.h19
-rw-r--r--include/drm/drm_edid.h1
-rw-r--r--include/drm/drm_scdc_helper.h27
5 files changed, 199 insertions, 2 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index d6f16c02afb5..99144f879a4f 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -37,6 +37,7 @@
37#include <drm/drm_edid.h> 37#include <drm/drm_edid.h>
38#include <drm/drm_encoder.h> 38#include <drm/drm_encoder.h>
39#include <drm/drm_displayid.h> 39#include <drm/drm_displayid.h>
40#include <drm/drm_scdc_helper.h>
40 41
41#include "drm_crtc_internal.h" 42#include "drm_crtc_internal.h"
42 43
@@ -3817,13 +3818,43 @@ EXPORT_SYMBOL(drm_default_rgb_quant_range);
3817static void drm_parse_hdmi_forum_vsdb(struct drm_connector *connector, 3818static void drm_parse_hdmi_forum_vsdb(struct drm_connector *connector,
3818 const u8 *hf_vsdb) 3819 const u8 *hf_vsdb)
3819{ 3820{
3820 struct drm_hdmi_info *hdmi = &connector->display_info.hdmi; 3821 struct drm_display_info *display = &connector->display_info;
3822 struct drm_hdmi_info *hdmi = &display->hdmi;
3821 3823
3822 if (hf_vsdb[6] & 0x80) { 3824 if (hf_vsdb[6] & 0x80) {
3823 hdmi->scdc.supported = true; 3825 hdmi->scdc.supported = true;
3824 if (hf_vsdb[6] & 0x40) 3826 if (hf_vsdb[6] & 0x40)
3825 hdmi->scdc.read_request = true; 3827 hdmi->scdc.read_request = true;
3826 } 3828 }
3829
3830 /*
3831 * All HDMI 2.0 monitors must support scrambling at rates > 340 MHz.
3832 * And as per the spec, three factors confirm this:
3833 * * Availability of a HF-VSDB block in EDID (check)
3834 * * Non zero Max_TMDS_Char_Rate filed in HF-VSDB (let's check)
3835 * * SCDC support available (let's check)
3836 * Lets check it out.
3837 */
3838
3839 if (hf_vsdb[5]) {
3840 /* max clock is 5000 KHz times block value */
3841 u32 max_tmds_clock = hf_vsdb[5] * 5000;
3842 struct drm_scdc *scdc = &hdmi->scdc;
3843
3844 if (max_tmds_clock > 340000) {
3845 display->max_tmds_clock = max_tmds_clock;
3846 DRM_DEBUG_KMS("HF-VSDB: max TMDS clock %d kHz\n",
3847 display->max_tmds_clock);
3848 }
3849
3850 if (scdc->supported) {
3851 scdc->scrambling.supported = true;
3852
3853 /* Few sinks support scrambling for cloks < 340M */
3854 if ((hf_vsdb[6] & 0x8))
3855 scdc->scrambling.low_rates = true;
3856 }
3857 }
3827} 3858}
3828 3859
3829static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector, 3860static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector,
diff --git a/drivers/gpu/drm/drm_scdc_helper.c b/drivers/gpu/drm/drm_scdc_helper.c
index c2dd33f89c17..3cd96a95736d 100644
--- a/drivers/gpu/drm/drm_scdc_helper.c
+++ b/drivers/gpu/drm/drm_scdc_helper.c
@@ -22,8 +22,10 @@
22 */ 22 */
23 23
24#include <linux/slab.h> 24#include <linux/slab.h>
25#include <linux/delay.h>
25 26
26#include <drm/drm_scdc_helper.h> 27#include <drm/drm_scdc_helper.h>
28#include <drm/drmP.h>
27 29
28/** 30/**
29 * DOC: scdc helpers 31 * DOC: scdc helpers
@@ -121,3 +123,122 @@ ssize_t drm_scdc_write(struct i2c_adapter *adapter, u8 offset,
121 return 0; 123 return 0;
122} 124}
123EXPORT_SYMBOL(drm_scdc_write); 125EXPORT_SYMBOL(drm_scdc_write);
126
127/**
128 * drm_scdc_check_scrambling_status - what is status of scrambling?
129 * @adapter: I2C adapter for DDC channel
130 *
131 * Reads the scrambler status over SCDC, and checks the
132 * scrambling status.
133 *
134 * Returns:
135 * True if the scrambling is enabled, false otherwise.
136 */
137
138bool drm_scdc_get_scrambling_status(struct i2c_adapter *adapter)
139{
140 u8 status;
141 int ret;
142
143 ret = drm_scdc_readb(adapter, SCDC_SCRAMBLER_STATUS, &status);
144 if (ret < 0) {
145 DRM_ERROR("Failed to read scrambling status, error %d\n", ret);
146 return false;
147 }
148
149 return status & SCDC_SCRAMBLING_STATUS;
150}
151EXPORT_SYMBOL(drm_scdc_get_scrambling_status);
152
153/**
154 * drm_scdc_set_scrambling - enable scrambling
155 * @adapter: I2C adapter for DDC channel
156 * @enable: bool to indicate if scrambling is to be enabled/disabled
157 *
158 * Writes the TMDS config register over SCDC channel, and:
159 * enables scrambling when enable = 1
160 * disables scrambling when enable = 0
161 *
162 * Returns:
163 * True if scrambling is set/reset successfully, false otherwise.
164 */
165
166bool drm_scdc_set_scrambling(struct i2c_adapter *adapter, bool enable)
167{
168 u8 config;
169 int ret;
170
171 ret = drm_scdc_readb(adapter, SCDC_TMDS_CONFIG, &config);
172 if (ret < 0) {
173 DRM_ERROR("Failed to read tmds config, err=%d\n", ret);
174 return false;
175 }
176
177 if (enable)
178 config |= SCDC_SCRAMBLING_ENABLE;
179 else
180 config &= ~SCDC_SCRAMBLING_ENABLE;
181
182 ret = drm_scdc_writeb(adapter, SCDC_TMDS_CONFIG, config);
183 if (ret < 0) {
184 DRM_ERROR("Failed to enable scrambling, error %d\n", ret);
185 return false;
186 }
187
188 return true;
189}
190EXPORT_SYMBOL(drm_scdc_set_scrambling);
191
192/**
193 * drm_scdc_set_high_tmds_clock_ratio - set TMDS clock ratio
194 * @adapter: I2C adapter for DDC channel
195 * @set: ret or reset the high clock ratio
196 *
197 * TMDS clock ratio calculations go like this:
198 * TMDS character = 10 bit TMDS encoded value
199 * TMDS character rate = The rate at which TMDS characters are transmitted(Mcsc)
200 * TMDS bit rate = 10x TMDS character rate
201 * As per the spec:
202 * TMDS clock rate for pixel clock < 340 MHz = 1x the character rate
203 * = 1/10 pixel clock rate
204 * TMDS clock rate for pixel clock > 340 MHz = 0.25x the character rate
205 * = 1/40 pixel clock rate
206 *
207 * Writes to the TMDS config register over SCDC channel, and:
208 * sets TMDS clock ratio to 1/40 when set = 1
209 * sets TMDS clock ratio to 1/10 when set = 0
210 *
211 * Returns:
212 * True if write is successful, false otherwise.
213 */
214bool drm_scdc_set_high_tmds_clock_ratio(struct i2c_adapter *adapter, bool set)
215{
216 u8 config;
217 int ret;
218
219 ret = drm_scdc_readb(adapter, SCDC_TMDS_CONFIG, &config);
220 if (ret < 0) {
221 DRM_ERROR("Failed to read tmds config, err=%d\n", ret);
222 return false;
223 }
224
225 if (set)
226 config |= SCDC_TMDS_BIT_CLOCK_RATIO_BY_40;
227 else
228 config &= ~SCDC_TMDS_BIT_CLOCK_RATIO_BY_40;
229
230 ret = drm_scdc_writeb(adapter, SCDC_TMDS_CONFIG, config);
231 if (ret < 0) {
232 DRM_ERROR("Failed to set TMDS clock ratio, error %d\n", ret);
233 return false;
234 }
235
236 /*
237 * The spec says that a source should wait minimum 1ms and maximum
238 * 100ms after writing the TMDS config for clock ratio. Lets allow a
239 * wait of upto 2ms here.
240 */
241 usleep_range(1000, 2000);
242 return true;
243}
244EXPORT_SYMBOL(drm_scdc_set_high_tmds_clock_ratio);
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index bf9d6f54ad16..f8b766d70a46 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -90,6 +90,20 @@ enum subpixel_order {
90 90
91}; 91};
92 92
93/**
94 * struct drm_scrambling: sink's scrambling support.
95 */
96struct drm_scrambling {
97 /**
98 * @supported: scrambling supported for rates > 340 Mhz.
99 */
100 bool supported;
101 /**
102 * @low_rates: scrambling supported for rates <= 340 Mhz.
103 */
104 bool low_rates;
105};
106
93/* 107/*
94 * struct drm_scdc - Information about scdc capabilities of a HDMI 2.0 sink 108 * struct drm_scdc - Information about scdc capabilities of a HDMI 2.0 sink
95 * 109 *
@@ -105,8 +119,13 @@ struct drm_scdc {
105 * @read_request: sink is capable of generating scdc read request. 119 * @read_request: sink is capable of generating scdc read request.
106 */ 120 */
107 bool read_request; 121 bool read_request;
122 /**
123 * @scrambling: sink's scrambling capabilities
124 */
125 struct drm_scrambling scrambling;
108}; 126};
109 127
128
110/** 129/**
111 * struct drm_hdmi_info - runtime information about the connected HDMI sink 130 * struct drm_hdmi_info - runtime information about the connected HDMI sink
112 * 131 *
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
index 3ead84d93792..7b9f48b62e07 100644
--- a/include/drm/drm_edid.h
+++ b/include/drm/drm_edid.h
@@ -476,5 +476,4 @@ void drm_edid_get_monitor_name(struct edid *edid, char *name,
476struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev, 476struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev,
477 int hsize, int vsize, int fresh, 477 int hsize, int vsize, int fresh,
478 bool rb); 478 bool rb);
479
480#endif /* __DRM_EDID_H__ */ 479#endif /* __DRM_EDID_H__ */
diff --git a/include/drm/drm_scdc_helper.h b/include/drm/drm_scdc_helper.h
index 9c52deb13df4..ab6bcfbceba9 100644
--- a/include/drm/drm_scdc_helper.h
+++ b/include/drm/drm_scdc_helper.h
@@ -129,4 +129,31 @@ static inline int drm_scdc_writeb(struct i2c_adapter *adapter, u8 offset,
129 return drm_scdc_write(adapter, offset, &value, sizeof(value)); 129 return drm_scdc_write(adapter, offset, &value, sizeof(value));
130} 130}
131 131
132/**
133 * drm_scdc_set_scrambling - enable scrambling
134 * @adapter: I2C adapter for DDC channel
135 * @enable: bool to indicate if scrambling is to be enabled/disabled
136 *
137 * Writes the TMDS config register over SCDC channel, and:
138 * enables scrambling when enable = 1
139 * disables scrambling when enable = 0
140 *
141 * Returns:
142 * True if scrambling is set/reset successfully, false otherwise.
143 */
144bool drm_scdc_set_scrambling(struct i2c_adapter *adapter, bool enable);
145
146/**
147 * drm_scdc_set_high_tmds_clock_ratio - set TMDS clock ratio
148 * @adapter: I2C adapter for DDC channel
149 * @set: ret or reset the high clock ratio
150 *
151 * Writes to the TMDS config register over SCDC channel, and:
152 * sets TMDS clock ratio to 1/40 when set = 1
153 * sets TMDS clock ratio to 1/10 when set = 0
154 *
155 * Returns:
156 * True if write is successful, false otherwise.
157 */
158bool drm_scdc_set_high_tmds_clock_ratio(struct i2c_adapter *adapter, bool set);
132#endif 159#endif