diff options
author | Shashank Sharma <shashank.sharma@intel.com> | 2017-03-13 07:24:02 -0400 |
---|---|---|
committer | Jani Nikula <jani.nikula@intel.com> | 2017-03-21 04:15:56 -0400 |
commit | 62c58af32c935a98a1e8d8ceb39a3a47b36fbbcd (patch) | |
tree | ea1dca1ec86bdb3f213f69f9899dd05e51cd2762 | |
parent | afa1c763653e0fd68f2d1e3dca869c9453d8ef06 (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.c | 33 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_scdc_helper.c | 121 | ||||
-rw-r--r-- | include/drm/drm_connector.h | 19 | ||||
-rw-r--r-- | include/drm/drm_edid.h | 1 | ||||
-rw-r--r-- | include/drm/drm_scdc_helper.h | 27 |
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); | |||
3817 | static void drm_parse_hdmi_forum_vsdb(struct drm_connector *connector, | 3818 | static 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 | ||
3829 | static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector, | 3860 | static 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 | } |
123 | EXPORT_SYMBOL(drm_scdc_write); | 125 | EXPORT_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 | |||
138 | bool 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 | } | ||
151 | EXPORT_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 | |||
166 | bool 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 | } | ||
190 | EXPORT_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 | */ | ||
214 | bool 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 | } | ||
244 | EXPORT_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 | */ | ||
96 | struct 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, | |||
476 | struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev, | 476 | struct 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 | */ | ||
144 | bool 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 | */ | ||
158 | bool drm_scdc_set_high_tmds_clock_ratio(struct i2c_adapter *adapter, bool set); | ||
132 | #endif | 159 | #endif |