Rev 4560 | Rev 5097 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
2351 | Serge | 1 | /* |
2 | * Copyright © 2006 Intel Corporation |
||
3 | * |
||
4 | * Permission is hereby granted, free of charge, to any person obtaining a |
||
5 | * copy of this software and associated documentation files (the "Software"), |
||
6 | * to deal in the Software without restriction, including without limitation |
||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||
8 | * and/or sell copies of the Software, and to permit persons to whom the |
||
9 | * Software is furnished to do so, subject to the following conditions: |
||
10 | * |
||
11 | * The above copyright notice and this permission notice (including the next |
||
12 | * paragraph) shall be included in all copies or substantial portions of the |
||
13 | * Software. |
||
14 | * |
||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||
20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||
21 | * SOFTWARE. |
||
22 | * |
||
23 | * Authors: |
||
24 | * Eric Anholt |
||
25 | * |
||
26 | */ |
||
5060 | serge | 27 | #include |
2351 | Serge | 28 | #include |
3031 | serge | 29 | #include |
2351 | Serge | 30 | #include "i915_drv.h" |
31 | #include "intel_bios.h" |
||
32 | |||
33 | #define SLAVE_ADDR1 0x70 |
||
34 | #define SLAVE_ADDR2 0x72 |
||
35 | |||
36 | static int panel_type; |
||
37 | |||
38 | static void * |
||
39 | find_section(struct bdb_header *bdb, int section_id) |
||
40 | { |
||
41 | u8 *base = (u8 *)bdb; |
||
42 | int index = 0; |
||
43 | u16 total, current_size; |
||
44 | u8 current_id; |
||
45 | |||
46 | /* skip to first section */ |
||
47 | index += bdb->header_size; |
||
48 | total = bdb->bdb_size; |
||
49 | |||
50 | /* walk the sections looking for section_id */ |
||
5060 | serge | 51 | while (index + 3 < total) { |
2351 | Serge | 52 | current_id = *(base + index); |
53 | index++; |
||
5060 | serge | 54 | |
2351 | Serge | 55 | current_size = *((u16 *)(base + index)); |
56 | index += 2; |
||
5060 | serge | 57 | |
58 | if (index + current_size > total) |
||
59 | return NULL; |
||
60 | |||
2351 | Serge | 61 | if (current_id == section_id) |
62 | return base + index; |
||
5060 | serge | 63 | |
2351 | Serge | 64 | index += current_size; |
65 | } |
||
66 | |||
67 | return NULL; |
||
68 | } |
||
69 | |||
70 | static u16 |
||
71 | get_blocksize(void *p) |
||
72 | { |
||
73 | u16 *block_ptr, block_size; |
||
74 | |||
75 | block_ptr = (u16 *)((char *)p - 2); |
||
76 | block_size = *block_ptr; |
||
77 | return block_size; |
||
78 | } |
||
79 | |||
80 | static void |
||
81 | fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode, |
||
82 | const struct lvds_dvo_timing *dvo_timing) |
||
83 | { |
||
84 | panel_fixed_mode->hdisplay = (dvo_timing->hactive_hi << 8) | |
||
85 | dvo_timing->hactive_lo; |
||
86 | panel_fixed_mode->hsync_start = panel_fixed_mode->hdisplay + |
||
87 | ((dvo_timing->hsync_off_hi << 8) | dvo_timing->hsync_off_lo); |
||
88 | panel_fixed_mode->hsync_end = panel_fixed_mode->hsync_start + |
||
89 | dvo_timing->hsync_pulse_width; |
||
90 | panel_fixed_mode->htotal = panel_fixed_mode->hdisplay + |
||
91 | ((dvo_timing->hblank_hi << 8) | dvo_timing->hblank_lo); |
||
92 | |||
93 | panel_fixed_mode->vdisplay = (dvo_timing->vactive_hi << 8) | |
||
94 | dvo_timing->vactive_lo; |
||
95 | panel_fixed_mode->vsync_start = panel_fixed_mode->vdisplay + |
||
96 | dvo_timing->vsync_off; |
||
97 | panel_fixed_mode->vsync_end = panel_fixed_mode->vsync_start + |
||
98 | dvo_timing->vsync_pulse_width; |
||
99 | panel_fixed_mode->vtotal = panel_fixed_mode->vdisplay + |
||
100 | ((dvo_timing->vblank_hi << 8) | dvo_timing->vblank_lo); |
||
101 | panel_fixed_mode->clock = dvo_timing->clock * 10; |
||
102 | panel_fixed_mode->type = DRM_MODE_TYPE_PREFERRED; |
||
103 | |||
104 | if (dvo_timing->hsync_positive) |
||
105 | panel_fixed_mode->flags |= DRM_MODE_FLAG_PHSYNC; |
||
106 | else |
||
107 | panel_fixed_mode->flags |= DRM_MODE_FLAG_NHSYNC; |
||
108 | |||
109 | if (dvo_timing->vsync_positive) |
||
110 | panel_fixed_mode->flags |= DRM_MODE_FLAG_PVSYNC; |
||
111 | else |
||
112 | panel_fixed_mode->flags |= DRM_MODE_FLAG_NVSYNC; |
||
113 | |||
114 | /* Some VBTs have bogus h/vtotal values */ |
||
115 | if (panel_fixed_mode->hsync_end > panel_fixed_mode->htotal) |
||
116 | panel_fixed_mode->htotal = panel_fixed_mode->hsync_end + 1; |
||
117 | if (panel_fixed_mode->vsync_end > panel_fixed_mode->vtotal) |
||
118 | panel_fixed_mode->vtotal = panel_fixed_mode->vsync_end + 1; |
||
119 | |||
120 | drm_mode_set_name(panel_fixed_mode); |
||
121 | } |
||
122 | |||
123 | static bool |
||
124 | lvds_dvo_timing_equal_size(const struct lvds_dvo_timing *a, |
||
125 | const struct lvds_dvo_timing *b) |
||
126 | { |
||
127 | if (a->hactive_hi != b->hactive_hi || |
||
128 | a->hactive_lo != b->hactive_lo) |
||
129 | return false; |
||
130 | |||
131 | if (a->hsync_off_hi != b->hsync_off_hi || |
||
132 | a->hsync_off_lo != b->hsync_off_lo) |
||
133 | return false; |
||
134 | |||
135 | if (a->hsync_pulse_width != b->hsync_pulse_width) |
||
136 | return false; |
||
137 | |||
138 | if (a->hblank_hi != b->hblank_hi || |
||
139 | a->hblank_lo != b->hblank_lo) |
||
140 | return false; |
||
141 | |||
142 | if (a->vactive_hi != b->vactive_hi || |
||
143 | a->vactive_lo != b->vactive_lo) |
||
144 | return false; |
||
145 | |||
146 | if (a->vsync_off != b->vsync_off) |
||
147 | return false; |
||
148 | |||
149 | if (a->vsync_pulse_width != b->vsync_pulse_width) |
||
150 | return false; |
||
151 | |||
152 | if (a->vblank_hi != b->vblank_hi || |
||
153 | a->vblank_lo != b->vblank_lo) |
||
154 | return false; |
||
155 | |||
156 | return true; |
||
157 | } |
||
158 | |||
159 | static const struct lvds_dvo_timing * |
||
160 | get_lvds_dvo_timing(const struct bdb_lvds_lfp_data *lvds_lfp_data, |
||
161 | const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs, |
||
162 | int index) |
||
163 | { |
||
164 | /* |
||
165 | * the size of fp_timing varies on the different platform. |
||
166 | * So calculate the DVO timing relative offset in LVDS data |
||
167 | * entry to get the DVO timing entry |
||
168 | */ |
||
169 | |||
170 | int lfp_data_size = |
||
171 | lvds_lfp_data_ptrs->ptr[1].dvo_timing_offset - |
||
172 | lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset; |
||
173 | int dvo_timing_offset = |
||
174 | lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset - |
||
175 | lvds_lfp_data_ptrs->ptr[0].fp_timing_offset; |
||
176 | char *entry = (char *)lvds_lfp_data->data + lfp_data_size * index; |
||
177 | |||
178 | return (struct lvds_dvo_timing *)(entry + dvo_timing_offset); |
||
179 | } |
||
180 | |||
3031 | serge | 181 | /* get lvds_fp_timing entry |
182 | * this function may return NULL if the corresponding entry is invalid |
||
183 | */ |
||
184 | static const struct lvds_fp_timing * |
||
185 | get_lvds_fp_timing(const struct bdb_header *bdb, |
||
186 | const struct bdb_lvds_lfp_data *data, |
||
187 | const struct bdb_lvds_lfp_data_ptrs *ptrs, |
||
188 | int index) |
||
189 | { |
||
190 | size_t data_ofs = (const u8 *)data - (const u8 *)bdb; |
||
191 | u16 data_size = ((const u16 *)data)[-1]; /* stored in header */ |
||
192 | size_t ofs; |
||
193 | |||
194 | if (index >= ARRAY_SIZE(ptrs->ptr)) |
||
195 | return NULL; |
||
196 | ofs = ptrs->ptr[index].fp_timing_offset; |
||
197 | if (ofs < data_ofs || |
||
198 | ofs + sizeof(struct lvds_fp_timing) > data_ofs + data_size) |
||
199 | return NULL; |
||
200 | return (const struct lvds_fp_timing *)((const u8 *)bdb + ofs); |
||
201 | } |
||
202 | |||
2351 | Serge | 203 | /* Try to find integrated panel data */ |
204 | static void |
||
205 | parse_lfp_panel_data(struct drm_i915_private *dev_priv, |
||
206 | struct bdb_header *bdb) |
||
207 | { |
||
208 | const struct bdb_lvds_options *lvds_options; |
||
209 | const struct bdb_lvds_lfp_data *lvds_lfp_data; |
||
210 | const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs; |
||
211 | const struct lvds_dvo_timing *panel_dvo_timing; |
||
3031 | serge | 212 | const struct lvds_fp_timing *fp_timing; |
2351 | Serge | 213 | struct drm_display_mode *panel_fixed_mode; |
5060 | serge | 214 | int i, downclock, drrs_mode; |
2351 | Serge | 215 | |
216 | lvds_options = find_section(bdb, BDB_LVDS_OPTIONS); |
||
217 | if (!lvds_options) |
||
218 | return; |
||
219 | |||
4104 | Serge | 220 | dev_priv->vbt.lvds_dither = lvds_options->pixel_dither; |
2351 | Serge | 221 | if (lvds_options->panel_type == 0xff) |
222 | return; |
||
223 | |||
224 | panel_type = lvds_options->panel_type; |
||
225 | |||
5060 | serge | 226 | drrs_mode = (lvds_options->dps_panel_type_bits |
227 | >> (panel_type * 2)) & MODE_MASK; |
||
228 | /* |
||
229 | * VBT has static DRRS = 0 and seamless DRRS = 2. |
||
230 | * The below piece of code is required to adjust vbt.drrs_type |
||
231 | * to match the enum drrs_support_type. |
||
232 | */ |
||
233 | switch (drrs_mode) { |
||
234 | case 0: |
||
235 | dev_priv->vbt.drrs_type = STATIC_DRRS_SUPPORT; |
||
236 | DRM_DEBUG_KMS("DRRS supported mode is static\n"); |
||
237 | break; |
||
238 | case 2: |
||
239 | dev_priv->vbt.drrs_type = SEAMLESS_DRRS_SUPPORT; |
||
240 | DRM_DEBUG_KMS("DRRS supported mode is seamless\n"); |
||
241 | break; |
||
242 | default: |
||
243 | dev_priv->vbt.drrs_type = DRRS_NOT_SUPPORTED; |
||
244 | DRM_DEBUG_KMS("DRRS not supported (VBT input)\n"); |
||
245 | break; |
||
246 | } |
||
247 | |||
2351 | Serge | 248 | lvds_lfp_data = find_section(bdb, BDB_LVDS_LFP_DATA); |
249 | if (!lvds_lfp_data) |
||
250 | return; |
||
251 | |||
252 | lvds_lfp_data_ptrs = find_section(bdb, BDB_LVDS_LFP_DATA_PTRS); |
||
253 | if (!lvds_lfp_data_ptrs) |
||
254 | return; |
||
255 | |||
4104 | Serge | 256 | dev_priv->vbt.lvds_vbt = 1; |
2351 | Serge | 257 | |
258 | panel_dvo_timing = get_lvds_dvo_timing(lvds_lfp_data, |
||
259 | lvds_lfp_data_ptrs, |
||
260 | lvds_options->panel_type); |
||
261 | |||
262 | panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL); |
||
263 | if (!panel_fixed_mode) |
||
264 | return; |
||
265 | |||
266 | fill_detail_timing_data(panel_fixed_mode, panel_dvo_timing); |
||
267 | |||
4104 | Serge | 268 | dev_priv->vbt.lfp_lvds_vbt_mode = panel_fixed_mode; |
2351 | Serge | 269 | |
270 | DRM_DEBUG_KMS("Found panel mode in BIOS VBT tables:\n"); |
||
271 | drm_mode_debug_printmodeline(panel_fixed_mode); |
||
272 | |||
273 | /* |
||
274 | * Iterate over the LVDS panel timing info to find the lowest clock |
||
275 | * for the native resolution. |
||
276 | */ |
||
277 | downclock = panel_dvo_timing->clock; |
||
278 | for (i = 0; i < 16; i++) { |
||
279 | const struct lvds_dvo_timing *dvo_timing; |
||
280 | |||
281 | dvo_timing = get_lvds_dvo_timing(lvds_lfp_data, |
||
282 | lvds_lfp_data_ptrs, |
||
283 | i); |
||
284 | if (lvds_dvo_timing_equal_size(dvo_timing, panel_dvo_timing) && |
||
285 | dvo_timing->clock < downclock) |
||
286 | downclock = dvo_timing->clock; |
||
287 | } |
||
288 | |||
5060 | serge | 289 | if (downclock < panel_dvo_timing->clock && i915.lvds_downclock) { |
2351 | Serge | 290 | dev_priv->lvds_downclock_avail = 1; |
291 | dev_priv->lvds_downclock = downclock * 10; |
||
292 | DRM_DEBUG_KMS("LVDS downclock is found in VBT. " |
||
293 | "Normal Clock %dKHz, downclock %dKHz\n", |
||
294 | panel_fixed_mode->clock, 10*downclock); |
||
295 | } |
||
3031 | serge | 296 | |
297 | fp_timing = get_lvds_fp_timing(bdb, lvds_lfp_data, |
||
298 | lvds_lfp_data_ptrs, |
||
299 | lvds_options->panel_type); |
||
300 | if (fp_timing) { |
||
301 | /* check the resolution, just to be sure */ |
||
302 | if (fp_timing->x_res == panel_fixed_mode->hdisplay && |
||
303 | fp_timing->y_res == panel_fixed_mode->vdisplay) { |
||
4104 | Serge | 304 | dev_priv->vbt.bios_lvds_val = fp_timing->lvds_reg_val; |
3031 | serge | 305 | DRM_DEBUG_KMS("VBT initial LVDS value %x\n", |
4104 | Serge | 306 | dev_priv->vbt.bios_lvds_val); |
3031 | serge | 307 | } |
308 | } |
||
2351 | Serge | 309 | } |
310 | |||
4560 | Serge | 311 | static void |
312 | parse_lfp_backlight(struct drm_i915_private *dev_priv, struct bdb_header *bdb) |
||
313 | { |
||
314 | const struct bdb_lfp_backlight_data *backlight_data; |
||
315 | const struct bdb_lfp_backlight_data_entry *entry; |
||
316 | |||
317 | backlight_data = find_section(bdb, BDB_LVDS_BACKLIGHT); |
||
318 | if (!backlight_data) |
||
319 | return; |
||
320 | |||
321 | if (backlight_data->entry_size != sizeof(backlight_data->data[0])) { |
||
322 | DRM_DEBUG_KMS("Unsupported backlight data entry size %u\n", |
||
323 | backlight_data->entry_size); |
||
324 | return; |
||
325 | } |
||
326 | |||
327 | entry = &backlight_data->data[panel_type]; |
||
328 | |||
5060 | serge | 329 | dev_priv->vbt.backlight.present = entry->type == BDB_BACKLIGHT_TYPE_PWM; |
330 | if (!dev_priv->vbt.backlight.present) { |
||
331 | DRM_DEBUG_KMS("PWM backlight not present in VBT (type %u)\n", |
||
332 | entry->type); |
||
333 | return; |
||
334 | } |
||
335 | |||
4560 | Serge | 336 | dev_priv->vbt.backlight.pwm_freq_hz = entry->pwm_freq_hz; |
337 | dev_priv->vbt.backlight.active_low_pwm = entry->active_low_pwm; |
||
5060 | serge | 338 | dev_priv->vbt.backlight.min_brightness = entry->min_brightness; |
4560 | Serge | 339 | DRM_DEBUG_KMS("VBT backlight PWM modulation frequency %u Hz, " |
340 | "active %s, min brightness %u, level %u\n", |
||
341 | dev_priv->vbt.backlight.pwm_freq_hz, |
||
342 | dev_priv->vbt.backlight.active_low_pwm ? "low" : "high", |
||
5060 | serge | 343 | dev_priv->vbt.backlight.min_brightness, |
4560 | Serge | 344 | backlight_data->level[panel_type]); |
345 | } |
||
346 | |||
2351 | Serge | 347 | /* Try to find sdvo panel data */ |
348 | static void |
||
349 | parse_sdvo_panel_data(struct drm_i915_private *dev_priv, |
||
350 | struct bdb_header *bdb) |
||
351 | { |
||
352 | struct lvds_dvo_timing *dvo_timing; |
||
353 | struct drm_display_mode *panel_fixed_mode; |
||
354 | int index; |
||
355 | |||
5060 | serge | 356 | index = i915.vbt_sdvo_panel_type; |
3031 | serge | 357 | if (index == -2) { |
358 | DRM_DEBUG_KMS("Ignore SDVO panel mode from BIOS VBT tables.\n"); |
||
359 | return; |
||
360 | } |
||
361 | |||
2351 | Serge | 362 | if (index == -1) { |
363 | struct bdb_sdvo_lvds_options *sdvo_lvds_options; |
||
364 | |||
365 | sdvo_lvds_options = find_section(bdb, BDB_SDVO_LVDS_OPTIONS); |
||
366 | if (!sdvo_lvds_options) |
||
367 | return; |
||
368 | |||
369 | index = sdvo_lvds_options->panel_type; |
||
370 | } |
||
371 | |||
372 | dvo_timing = find_section(bdb, BDB_SDVO_PANEL_DTDS); |
||
373 | if (!dvo_timing) |
||
374 | return; |
||
375 | |||
376 | panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL); |
||
377 | if (!panel_fixed_mode) |
||
378 | return; |
||
379 | |||
380 | fill_detail_timing_data(panel_fixed_mode, dvo_timing + index); |
||
381 | |||
4104 | Serge | 382 | dev_priv->vbt.sdvo_lvds_vbt_mode = panel_fixed_mode; |
2351 | Serge | 383 | |
384 | DRM_DEBUG_KMS("Found SDVO panel mode in BIOS VBT tables:\n"); |
||
385 | drm_mode_debug_printmodeline(panel_fixed_mode); |
||
386 | } |
||
387 | |||
388 | static int intel_bios_ssc_frequency(struct drm_device *dev, |
||
389 | bool alternate) |
||
390 | { |
||
391 | switch (INTEL_INFO(dev)->gen) { |
||
392 | case 2: |
||
4560 | Serge | 393 | return alternate ? 66667 : 48000; |
2351 | Serge | 394 | case 3: |
395 | case 4: |
||
4560 | Serge | 396 | return alternate ? 100000 : 96000; |
2351 | Serge | 397 | default: |
4560 | Serge | 398 | return alternate ? 100000 : 120000; |
2351 | Serge | 399 | } |
400 | } |
||
401 | |||
402 | static void |
||
403 | parse_general_features(struct drm_i915_private *dev_priv, |
||
404 | struct bdb_header *bdb) |
||
405 | { |
||
406 | struct drm_device *dev = dev_priv->dev; |
||
407 | struct bdb_general_features *general; |
||
408 | |||
409 | general = find_section(bdb, BDB_GENERAL_FEATURES); |
||
410 | if (general) { |
||
4104 | Serge | 411 | dev_priv->vbt.int_tv_support = general->int_tv_support; |
412 | dev_priv->vbt.int_crt_support = general->int_crt_support; |
||
413 | dev_priv->vbt.lvds_use_ssc = general->enable_ssc; |
||
414 | dev_priv->vbt.lvds_ssc_freq = |
||
2351 | Serge | 415 | intel_bios_ssc_frequency(dev, general->ssc_freq); |
4104 | Serge | 416 | dev_priv->vbt.display_clock_mode = general->display_clock_mode; |
417 | dev_priv->vbt.fdi_rx_polarity_inverted = general->fdi_rx_polarity_inverted; |
||
3746 | Serge | 418 | DRM_DEBUG_KMS("BDB_GENERAL_FEATURES int_tv_support %d int_crt_support %d lvds_use_ssc %d lvds_ssc_freq %d display_clock_mode %d fdi_rx_polarity_inverted %d\n", |
4104 | Serge | 419 | dev_priv->vbt.int_tv_support, |
420 | dev_priv->vbt.int_crt_support, |
||
421 | dev_priv->vbt.lvds_use_ssc, |
||
422 | dev_priv->vbt.lvds_ssc_freq, |
||
423 | dev_priv->vbt.display_clock_mode, |
||
424 | dev_priv->vbt.fdi_rx_polarity_inverted); |
||
2351 | Serge | 425 | } |
426 | } |
||
427 | |||
428 | static void |
||
429 | parse_general_definitions(struct drm_i915_private *dev_priv, |
||
430 | struct bdb_header *bdb) |
||
431 | { |
||
432 | struct bdb_general_definitions *general; |
||
433 | |||
434 | general = find_section(bdb, BDB_GENERAL_DEFINITIONS); |
||
435 | if (general) { |
||
436 | u16 block_size = get_blocksize(general); |
||
437 | if (block_size >= sizeof(*general)) { |
||
438 | int bus_pin = general->crt_ddc_gmbus_pin; |
||
439 | DRM_DEBUG_KMS("crt_ddc_bus_pin: %d\n", bus_pin); |
||
3031 | serge | 440 | if (intel_gmbus_is_port_valid(bus_pin)) |
4104 | Serge | 441 | dev_priv->vbt.crt_ddc_pin = bus_pin; |
2351 | Serge | 442 | } else { |
443 | DRM_DEBUG_KMS("BDB_GD too small (%d). Invalid.\n", |
||
444 | block_size); |
||
445 | } |
||
446 | } |
||
447 | } |
||
448 | |||
449 | static void |
||
450 | parse_sdvo_device_mapping(struct drm_i915_private *dev_priv, |
||
451 | struct bdb_header *bdb) |
||
452 | { |
||
453 | struct sdvo_device_mapping *p_mapping; |
||
454 | struct bdb_general_definitions *p_defs; |
||
4560 | Serge | 455 | union child_device_config *p_child; |
2351 | Serge | 456 | int i, child_device_num, count; |
457 | u16 block_size; |
||
458 | |||
459 | p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS); |
||
460 | if (!p_defs) { |
||
461 | DRM_DEBUG_KMS("No general definition block is found, unable to construct sdvo mapping.\n"); |
||
462 | return; |
||
463 | } |
||
464 | /* judge whether the size of child device meets the requirements. |
||
465 | * If the child device size obtained from general definition block |
||
466 | * is different with sizeof(struct child_device_config), skip the |
||
467 | * parsing of sdvo device info |
||
468 | */ |
||
469 | if (p_defs->child_dev_size != sizeof(*p_child)) { |
||
470 | /* different child dev size . Ignore it */ |
||
471 | DRM_DEBUG_KMS("different child size is found. Invalid.\n"); |
||
472 | return; |
||
473 | } |
||
474 | /* get the block size of general definitions */ |
||
475 | block_size = get_blocksize(p_defs); |
||
476 | /* get the number of child device */ |
||
477 | child_device_num = (block_size - sizeof(*p_defs)) / |
||
478 | sizeof(*p_child); |
||
479 | count = 0; |
||
480 | for (i = 0; i < child_device_num; i++) { |
||
481 | p_child = &(p_defs->devices[i]); |
||
4560 | Serge | 482 | if (!p_child->old.device_type) { |
2351 | Serge | 483 | /* skip the device block if device type is invalid */ |
484 | continue; |
||
485 | } |
||
4560 | Serge | 486 | if (p_child->old.slave_addr != SLAVE_ADDR1 && |
487 | p_child->old.slave_addr != SLAVE_ADDR2) { |
||
2351 | Serge | 488 | /* |
489 | * If the slave address is neither 0x70 nor 0x72, |
||
490 | * it is not a SDVO device. Skip it. |
||
491 | */ |
||
492 | continue; |
||
493 | } |
||
4560 | Serge | 494 | if (p_child->old.dvo_port != DEVICE_PORT_DVOB && |
495 | p_child->old.dvo_port != DEVICE_PORT_DVOC) { |
||
2351 | Serge | 496 | /* skip the incorrect SDVO port */ |
497 | DRM_DEBUG_KMS("Incorrect SDVO port. Skip it\n"); |
||
498 | continue; |
||
499 | } |
||
500 | DRM_DEBUG_KMS("the SDVO device with slave addr %2x is found on" |
||
501 | " %s port\n", |
||
4560 | Serge | 502 | p_child->old.slave_addr, |
503 | (p_child->old.dvo_port == DEVICE_PORT_DVOB) ? |
||
2351 | Serge | 504 | "SDVOB" : "SDVOC"); |
4560 | Serge | 505 | p_mapping = &(dev_priv->sdvo_mappings[p_child->old.dvo_port - 1]); |
2351 | Serge | 506 | if (!p_mapping->initialized) { |
4560 | Serge | 507 | p_mapping->dvo_port = p_child->old.dvo_port; |
508 | p_mapping->slave_addr = p_child->old.slave_addr; |
||
509 | p_mapping->dvo_wiring = p_child->old.dvo_wiring; |
||
510 | p_mapping->ddc_pin = p_child->old.ddc_pin; |
||
511 | p_mapping->i2c_pin = p_child->old.i2c_pin; |
||
2351 | Serge | 512 | p_mapping->initialized = 1; |
513 | DRM_DEBUG_KMS("SDVO device: dvo=%x, addr=%x, wiring=%d, ddc_pin=%d, i2c_pin=%d\n", |
||
514 | p_mapping->dvo_port, |
||
515 | p_mapping->slave_addr, |
||
516 | p_mapping->dvo_wiring, |
||
517 | p_mapping->ddc_pin, |
||
518 | p_mapping->i2c_pin); |
||
519 | } else { |
||
520 | DRM_DEBUG_KMS("Maybe one SDVO port is shared by " |
||
521 | "two SDVO device.\n"); |
||
522 | } |
||
4560 | Serge | 523 | if (p_child->old.slave2_addr) { |
2351 | Serge | 524 | /* Maybe this is a SDVO device with multiple inputs */ |
525 | /* And the mapping info is not added */ |
||
526 | DRM_DEBUG_KMS("there exists the slave2_addr. Maybe this" |
||
527 | " is a SDVO device with multiple inputs.\n"); |
||
528 | } |
||
529 | count++; |
||
530 | } |
||
531 | |||
532 | if (!count) { |
||
533 | /* No SDVO device info is found */ |
||
534 | DRM_DEBUG_KMS("No SDVO device info is found in VBT\n"); |
||
535 | } |
||
536 | return; |
||
537 | } |
||
538 | |||
539 | static void |
||
540 | parse_driver_features(struct drm_i915_private *dev_priv, |
||
541 | struct bdb_header *bdb) |
||
542 | { |
||
543 | struct bdb_driver_features *driver; |
||
544 | |||
545 | driver = find_section(bdb, BDB_DRIVER_FEATURES); |
||
546 | if (!driver) |
||
547 | return; |
||
548 | |||
4560 | Serge | 549 | if (driver->lvds_config == BDB_DRIVER_FEATURE_EDP) |
4104 | Serge | 550 | dev_priv->vbt.edp_support = 1; |
2351 | Serge | 551 | |
552 | if (driver->dual_frequency) |
||
553 | dev_priv->render_reclock_avail = true; |
||
5060 | serge | 554 | |
555 | DRM_DEBUG_KMS("DRRS State Enabled:%d\n", driver->drrs_enabled); |
||
556 | /* |
||
557 | * If DRRS is not supported, drrs_type has to be set to 0. |
||
558 | * This is because, VBT is configured in such a way that |
||
559 | * static DRRS is 0 and DRRS not supported is represented by |
||
560 | * driver->drrs_enabled=false |
||
561 | */ |
||
562 | if (!driver->drrs_enabled) |
||
563 | dev_priv->vbt.drrs_type = DRRS_NOT_SUPPORTED; |
||
2351 | Serge | 564 | } |
565 | |||
566 | static void |
||
567 | parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb) |
||
568 | { |
||
569 | struct bdb_edp *edp; |
||
570 | struct edp_power_seq *edp_pps; |
||
571 | struct edp_link_params *edp_link_params; |
||
572 | |||
573 | edp = find_section(bdb, BDB_EDP); |
||
574 | if (!edp) { |
||
4560 | Serge | 575 | if (dev_priv->vbt.edp_support) |
3120 | serge | 576 | DRM_DEBUG_KMS("No eDP BDB found but eDP panel supported.\n"); |
2351 | Serge | 577 | return; |
578 | } |
||
579 | |||
580 | switch ((edp->color_depth >> (panel_type * 2)) & 3) { |
||
581 | case EDP_18BPP: |
||
4104 | Serge | 582 | dev_priv->vbt.edp_bpp = 18; |
2351 | Serge | 583 | break; |
584 | case EDP_24BPP: |
||
4104 | Serge | 585 | dev_priv->vbt.edp_bpp = 24; |
2351 | Serge | 586 | break; |
587 | case EDP_30BPP: |
||
4104 | Serge | 588 | dev_priv->vbt.edp_bpp = 30; |
2351 | Serge | 589 | break; |
590 | } |
||
591 | |||
592 | /* Get the eDP sequencing and link info */ |
||
593 | edp_pps = &edp->power_seqs[panel_type]; |
||
594 | edp_link_params = &edp->link_params[panel_type]; |
||
595 | |||
4104 | Serge | 596 | dev_priv->vbt.edp_pps = *edp_pps; |
2351 | Serge | 597 | |
5060 | serge | 598 | switch (edp_link_params->rate) { |
599 | case EDP_RATE_1_62: |
||
600 | dev_priv->vbt.edp_rate = DP_LINK_BW_1_62; |
||
601 | break; |
||
602 | case EDP_RATE_2_7: |
||
603 | dev_priv->vbt.edp_rate = DP_LINK_BW_2_7; |
||
604 | break; |
||
605 | default: |
||
606 | DRM_DEBUG_KMS("VBT has unknown eDP link rate value %u\n", |
||
607 | edp_link_params->rate); |
||
608 | break; |
||
609 | } |
||
610 | |||
2351 | Serge | 611 | switch (edp_link_params->lanes) { |
5060 | serge | 612 | case EDP_LANE_1: |
4104 | Serge | 613 | dev_priv->vbt.edp_lanes = 1; |
2351 | Serge | 614 | break; |
5060 | serge | 615 | case EDP_LANE_2: |
4104 | Serge | 616 | dev_priv->vbt.edp_lanes = 2; |
2351 | Serge | 617 | break; |
5060 | serge | 618 | case EDP_LANE_4: |
4104 | Serge | 619 | dev_priv->vbt.edp_lanes = 4; |
2351 | Serge | 620 | break; |
5060 | serge | 621 | default: |
622 | DRM_DEBUG_KMS("VBT has unknown eDP lane count value %u\n", |
||
623 | edp_link_params->lanes); |
||
624 | break; |
||
2351 | Serge | 625 | } |
5060 | serge | 626 | |
2351 | Serge | 627 | switch (edp_link_params->preemphasis) { |
5060 | serge | 628 | case EDP_PREEMPHASIS_NONE: |
4104 | Serge | 629 | dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPHASIS_0; |
2351 | Serge | 630 | break; |
5060 | serge | 631 | case EDP_PREEMPHASIS_3_5dB: |
4104 | Serge | 632 | dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPHASIS_3_5; |
2351 | Serge | 633 | break; |
5060 | serge | 634 | case EDP_PREEMPHASIS_6dB: |
4104 | Serge | 635 | dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPHASIS_6; |
2351 | Serge | 636 | break; |
5060 | serge | 637 | case EDP_PREEMPHASIS_9_5dB: |
4104 | Serge | 638 | dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPHASIS_9_5; |
2351 | Serge | 639 | break; |
5060 | serge | 640 | default: |
641 | DRM_DEBUG_KMS("VBT has unknown eDP pre-emphasis value %u\n", |
||
642 | edp_link_params->preemphasis); |
||
643 | break; |
||
2351 | Serge | 644 | } |
5060 | serge | 645 | |
2351 | Serge | 646 | switch (edp_link_params->vswing) { |
5060 | serge | 647 | case EDP_VSWING_0_4V: |
4104 | Serge | 648 | dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_400; |
2351 | Serge | 649 | break; |
5060 | serge | 650 | case EDP_VSWING_0_6V: |
4104 | Serge | 651 | dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_600; |
2351 | Serge | 652 | break; |
5060 | serge | 653 | case EDP_VSWING_0_8V: |
4104 | Serge | 654 | dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_800; |
2351 | Serge | 655 | break; |
5060 | serge | 656 | case EDP_VSWING_1_2V: |
4104 | Serge | 657 | dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_1200; |
2351 | Serge | 658 | break; |
5060 | serge | 659 | default: |
660 | DRM_DEBUG_KMS("VBT has unknown eDP voltage swing value %u\n", |
||
661 | edp_link_params->vswing); |
||
662 | break; |
||
2351 | Serge | 663 | } |
664 | } |
||
665 | |||
5060 | serge | 666 | static u8 *goto_next_sequence(u8 *data, int *size) |
667 | { |
||
668 | u16 len; |
||
669 | int tmp = *size; |
||
670 | |||
671 | if (--tmp < 0) |
||
672 | return NULL; |
||
673 | |||
674 | /* goto first element */ |
||
675 | data++; |
||
676 | while (1) { |
||
677 | switch (*data) { |
||
678 | case MIPI_SEQ_ELEM_SEND_PKT: |
||
679 | /* |
||
680 | * skip by this element payload size |
||
681 | * skip elem id, command flag and data type |
||
682 | */ |
||
683 | tmp -= 5; |
||
684 | if (tmp < 0) |
||
685 | return NULL; |
||
686 | |||
687 | data += 3; |
||
688 | len = *((u16 *)data); |
||
689 | |||
690 | tmp -= len; |
||
691 | if (tmp < 0) |
||
692 | return NULL; |
||
693 | |||
694 | /* skip by len */ |
||
695 | data = data + 2 + len; |
||
696 | break; |
||
697 | case MIPI_SEQ_ELEM_DELAY: |
||
698 | /* skip by elem id, and delay is 4 bytes */ |
||
699 | tmp -= 5; |
||
700 | if (tmp < 0) |
||
701 | return NULL; |
||
702 | |||
703 | data += 5; |
||
704 | break; |
||
705 | case MIPI_SEQ_ELEM_GPIO: |
||
706 | tmp -= 3; |
||
707 | if (tmp < 0) |
||
708 | return NULL; |
||
709 | |||
710 | data += 3; |
||
711 | break; |
||
712 | default: |
||
713 | DRM_ERROR("Unknown element\n"); |
||
714 | return NULL; |
||
715 | } |
||
716 | |||
717 | /* end of sequence ? */ |
||
718 | if (*data == 0) |
||
719 | break; |
||
720 | } |
||
721 | |||
722 | /* goto next sequence or end of block byte */ |
||
723 | if (--tmp < 0) |
||
724 | return NULL; |
||
725 | |||
726 | data++; |
||
727 | |||
728 | /* update amount of data left for the sequence block to be parsed */ |
||
729 | *size = tmp; |
||
730 | return data; |
||
731 | } |
||
732 | |||
2351 | Serge | 733 | static void |
4560 | Serge | 734 | parse_mipi(struct drm_i915_private *dev_priv, struct bdb_header *bdb) |
735 | { |
||
5060 | serge | 736 | struct bdb_mipi_config *start; |
737 | struct bdb_mipi_sequence *sequence; |
||
738 | struct mipi_config *config; |
||
739 | struct mipi_pps_data *pps; |
||
740 | u8 *data, *seq_data; |
||
741 | int i, panel_id, seq_size; |
||
742 | u16 block_size; |
||
4560 | Serge | 743 | |
5060 | serge | 744 | /* parse MIPI blocks only if LFP type is MIPI */ |
745 | if (!dev_priv->vbt.has_mipi) |
||
4560 | Serge | 746 | return; |
5060 | serge | 747 | |
748 | /* Initialize this to undefined indicating no generic MIPI support */ |
||
749 | dev_priv->vbt.dsi.panel_id = MIPI_DSI_UNDEFINED_PANEL_ID; |
||
750 | |||
751 | /* Block #40 is already parsed and panel_fixed_mode is |
||
752 | * stored in dev_priv->lfp_lvds_vbt_mode |
||
753 | * resuse this when needed |
||
754 | */ |
||
755 | |||
756 | /* Parse #52 for panel index used from panel_type already |
||
757 | * parsed |
||
758 | */ |
||
759 | start = find_section(bdb, BDB_MIPI_CONFIG); |
||
760 | if (!start) { |
||
761 | DRM_DEBUG_KMS("No MIPI config BDB found"); |
||
762 | return; |
||
4560 | Serge | 763 | } |
764 | |||
5060 | serge | 765 | DRM_DEBUG_DRIVER("Found MIPI Config block, panel index = %d\n", |
766 | panel_type); |
||
767 | |||
768 | /* |
||
769 | * get hold of the correct configuration block and pps data as per |
||
770 | * the panel_type as index |
||
771 | */ |
||
772 | config = &start->config[panel_type]; |
||
773 | pps = &start->pps[panel_type]; |
||
774 | |||
775 | /* store as of now full data. Trim when we realise all is not needed */ |
||
776 | dev_priv->vbt.dsi.config = kmemdup(config, sizeof(struct mipi_config), GFP_KERNEL); |
||
777 | if (!dev_priv->vbt.dsi.config) |
||
778 | return; |
||
779 | |||
780 | dev_priv->vbt.dsi.pps = kmemdup(pps, sizeof(struct mipi_pps_data), GFP_KERNEL); |
||
781 | if (!dev_priv->vbt.dsi.pps) { |
||
782 | kfree(dev_priv->vbt.dsi.config); |
||
783 | return; |
||
784 | } |
||
785 | |||
786 | /* We have mandatory mipi config blocks. Initialize as generic panel */ |
||
787 | dev_priv->vbt.dsi.panel_id = MIPI_DSI_GENERIC_PANEL_ID; |
||
788 | |||
789 | /* Check if we have sequence block as well */ |
||
790 | sequence = find_section(bdb, BDB_MIPI_SEQUENCE); |
||
791 | if (!sequence) { |
||
792 | DRM_DEBUG_KMS("No MIPI Sequence found, parsing complete\n"); |
||
793 | return; |
||
794 | } |
||
795 | |||
796 | DRM_DEBUG_DRIVER("Found MIPI sequence block\n"); |
||
797 | |||
798 | block_size = get_blocksize(sequence); |
||
799 | |||
800 | /* |
||
801 | * parse the sequence block for individual sequences |
||
802 | */ |
||
803 | dev_priv->vbt.dsi.seq_version = sequence->version; |
||
804 | |||
805 | seq_data = &sequence->data[0]; |
||
806 | |||
807 | /* |
||
808 | * sequence block is variable length and hence we need to parse and |
||
809 | * get the sequence data for specific panel id |
||
810 | */ |
||
811 | for (i = 0; i < MAX_MIPI_CONFIGURATIONS; i++) { |
||
812 | panel_id = *seq_data; |
||
813 | seq_size = *((u16 *) (seq_data + 1)); |
||
814 | if (panel_id == panel_type) |
||
815 | break; |
||
816 | |||
817 | /* skip the sequence including seq header of 3 bytes */ |
||
818 | seq_data = seq_data + 3 + seq_size; |
||
819 | if ((seq_data - &sequence->data[0]) > block_size) { |
||
820 | DRM_ERROR("Sequence start is beyond sequence block size, corrupted sequence block\n"); |
||
821 | return; |
||
822 | } |
||
823 | } |
||
824 | |||
825 | if (i == MAX_MIPI_CONFIGURATIONS) { |
||
826 | DRM_ERROR("Sequence block detected but no valid configuration\n"); |
||
827 | return; |
||
828 | } |
||
829 | |||
830 | /* check if found sequence is completely within the sequence block |
||
831 | * just being paranoid */ |
||
832 | if (seq_size > block_size) { |
||
833 | DRM_ERROR("Corrupted sequence/size, bailing out\n"); |
||
834 | return; |
||
835 | } |
||
836 | |||
837 | /* skip the panel id(1 byte) and seq size(2 bytes) */ |
||
838 | dev_priv->vbt.dsi.data = kmemdup(seq_data + 3, seq_size, GFP_KERNEL); |
||
839 | if (!dev_priv->vbt.dsi.data) |
||
840 | return; |
||
841 | |||
842 | /* |
||
843 | * loop into the sequence data and split into multiple sequneces |
||
844 | * There are only 5 types of sequences as of now |
||
845 | */ |
||
846 | data = dev_priv->vbt.dsi.data; |
||
847 | dev_priv->vbt.dsi.size = seq_size; |
||
848 | |||
849 | /* two consecutive 0x00 indicate end of all sequences */ |
||
850 | while (1) { |
||
851 | int seq_id = *data; |
||
852 | if (MIPI_SEQ_MAX > seq_id && seq_id > MIPI_SEQ_UNDEFINED) { |
||
853 | dev_priv->vbt.dsi.sequence[seq_id] = data; |
||
854 | DRM_DEBUG_DRIVER("Found mipi sequence - %d\n", seq_id); |
||
855 | } else { |
||
856 | DRM_ERROR("undefined sequence\n"); |
||
857 | goto err; |
||
858 | } |
||
859 | |||
860 | /* partial parsing to skip elements */ |
||
861 | data = goto_next_sequence(data, &seq_size); |
||
862 | |||
863 | if (data == NULL) { |
||
864 | DRM_ERROR("Sequence elements going beyond block itself. Sequence block parsing failed\n"); |
||
865 | goto err; |
||
866 | } |
||
867 | |||
868 | if (*data == 0) |
||
869 | break; /* end of sequence reached */ |
||
870 | } |
||
871 | |||
872 | DRM_DEBUG_DRIVER("MIPI related vbt parsing complete\n"); |
||
873 | return; |
||
874 | err: |
||
875 | kfree(dev_priv->vbt.dsi.data); |
||
876 | dev_priv->vbt.dsi.data = NULL; |
||
877 | |||
878 | /* error during parsing so set all pointers to null |
||
879 | * because of partial parsing */ |
||
880 | memset(dev_priv->vbt.dsi.sequence, 0, sizeof(dev_priv->vbt.dsi.sequence)); |
||
4560 | Serge | 881 | } |
882 | |||
883 | static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port, |
||
884 | struct bdb_header *bdb) |
||
885 | { |
||
886 | union child_device_config *it, *child = NULL; |
||
887 | struct ddi_vbt_port_info *info = &dev_priv->vbt.ddi_port_info[port]; |
||
888 | uint8_t hdmi_level_shift; |
||
889 | int i, j; |
||
890 | bool is_dvi, is_hdmi, is_dp, is_edp, is_crt; |
||
891 | uint8_t aux_channel; |
||
892 | /* Each DDI port can have more than one value on the "DVO Port" field, |
||
893 | * so look for all the possible values for each port and abort if more |
||
894 | * than one is found. */ |
||
895 | int dvo_ports[][2] = { |
||
896 | {DVO_PORT_HDMIA, DVO_PORT_DPA}, |
||
897 | {DVO_PORT_HDMIB, DVO_PORT_DPB}, |
||
898 | {DVO_PORT_HDMIC, DVO_PORT_DPC}, |
||
899 | {DVO_PORT_HDMID, DVO_PORT_DPD}, |
||
900 | {DVO_PORT_CRT, -1 /* Port E can only be DVO_PORT_CRT */ }, |
||
901 | }; |
||
902 | |||
903 | /* Find the child device to use, abort if more than one found. */ |
||
904 | for (i = 0; i < dev_priv->vbt.child_dev_num; i++) { |
||
905 | it = dev_priv->vbt.child_dev + i; |
||
906 | |||
907 | for (j = 0; j < 2; j++) { |
||
908 | if (dvo_ports[port][j] == -1) |
||
909 | break; |
||
910 | |||
911 | if (it->common.dvo_port == dvo_ports[port][j]) { |
||
912 | if (child) { |
||
913 | DRM_DEBUG_KMS("More than one child device for port %c in VBT.\n", |
||
914 | port_name(port)); |
||
915 | return; |
||
916 | } |
||
917 | child = it; |
||
918 | } |
||
919 | } |
||
920 | } |
||
921 | if (!child) |
||
922 | return; |
||
923 | |||
924 | aux_channel = child->raw[25]; |
||
925 | |||
926 | is_dvi = child->common.device_type & DEVICE_TYPE_TMDS_DVI_SIGNALING; |
||
927 | is_dp = child->common.device_type & DEVICE_TYPE_DISPLAYPORT_OUTPUT; |
||
928 | is_crt = child->common.device_type & DEVICE_TYPE_ANALOG_OUTPUT; |
||
929 | is_hdmi = is_dvi && (child->common.device_type & DEVICE_TYPE_NOT_HDMI_OUTPUT) == 0; |
||
930 | is_edp = is_dp && (child->common.device_type & DEVICE_TYPE_INTERNAL_CONNECTOR); |
||
931 | |||
932 | info->supports_dvi = is_dvi; |
||
933 | info->supports_hdmi = is_hdmi; |
||
934 | info->supports_dp = is_dp; |
||
935 | |||
936 | DRM_DEBUG_KMS("Port %c VBT info: DP:%d HDMI:%d DVI:%d EDP:%d CRT:%d\n", |
||
937 | port_name(port), is_dp, is_hdmi, is_dvi, is_edp, is_crt); |
||
938 | |||
939 | if (is_edp && is_dvi) |
||
940 | DRM_DEBUG_KMS("Internal DP port %c is TMDS compatible\n", |
||
941 | port_name(port)); |
||
942 | if (is_crt && port != PORT_E) |
||
943 | DRM_DEBUG_KMS("Port %c is analog\n", port_name(port)); |
||
944 | if (is_crt && (is_dvi || is_dp)) |
||
945 | DRM_DEBUG_KMS("Analog port %c is also DP or TMDS compatible\n", |
||
946 | port_name(port)); |
||
947 | if (is_dvi && (port == PORT_A || port == PORT_E)) |
||
948 | DRM_DEBUG_KMS("Port %c is TMDS compabile\n", port_name(port)); |
||
949 | if (!is_dvi && !is_dp && !is_crt) |
||
950 | DRM_DEBUG_KMS("Port %c is not DP/TMDS/CRT compatible\n", |
||
951 | port_name(port)); |
||
952 | if (is_edp && (port == PORT_B || port == PORT_C || port == PORT_E)) |
||
953 | DRM_DEBUG_KMS("Port %c is internal DP\n", port_name(port)); |
||
954 | |||
955 | if (is_dvi) { |
||
956 | if (child->common.ddc_pin == 0x05 && port != PORT_B) |
||
957 | DRM_DEBUG_KMS("Unexpected DDC pin for port B\n"); |
||
958 | if (child->common.ddc_pin == 0x04 && port != PORT_C) |
||
959 | DRM_DEBUG_KMS("Unexpected DDC pin for port C\n"); |
||
960 | if (child->common.ddc_pin == 0x06 && port != PORT_D) |
||
961 | DRM_DEBUG_KMS("Unexpected DDC pin for port D\n"); |
||
962 | } |
||
963 | |||
964 | if (is_dp) { |
||
965 | if (aux_channel == 0x40 && port != PORT_A) |
||
966 | DRM_DEBUG_KMS("Unexpected AUX channel for port A\n"); |
||
967 | if (aux_channel == 0x10 && port != PORT_B) |
||
968 | DRM_DEBUG_KMS("Unexpected AUX channel for port B\n"); |
||
969 | if (aux_channel == 0x20 && port != PORT_C) |
||
970 | DRM_DEBUG_KMS("Unexpected AUX channel for port C\n"); |
||
971 | if (aux_channel == 0x30 && port != PORT_D) |
||
972 | DRM_DEBUG_KMS("Unexpected AUX channel for port D\n"); |
||
973 | } |
||
974 | |||
975 | if (bdb->version >= 158) { |
||
976 | /* The VBT HDMI level shift values match the table we have. */ |
||
977 | hdmi_level_shift = child->raw[7] & 0xF; |
||
978 | if (hdmi_level_shift < 0xC) { |
||
979 | DRM_DEBUG_KMS("VBT HDMI level shift for port %c: %d\n", |
||
980 | port_name(port), |
||
981 | hdmi_level_shift); |
||
982 | info->hdmi_level_shift = hdmi_level_shift; |
||
983 | } |
||
984 | } |
||
985 | } |
||
986 | |||
987 | static void parse_ddi_ports(struct drm_i915_private *dev_priv, |
||
988 | struct bdb_header *bdb) |
||
989 | { |
||
990 | struct drm_device *dev = dev_priv->dev; |
||
991 | enum port port; |
||
992 | |||
993 | if (!HAS_DDI(dev)) |
||
994 | return; |
||
995 | |||
996 | if (!dev_priv->vbt.child_dev_num) |
||
997 | return; |
||
998 | |||
999 | if (bdb->version < 155) |
||
1000 | return; |
||
1001 | |||
1002 | for (port = PORT_A; port < I915_MAX_PORTS; port++) |
||
1003 | parse_ddi_port(dev_priv, port, bdb); |
||
1004 | } |
||
1005 | |||
1006 | static void |
||
2351 | Serge | 1007 | parse_device_mapping(struct drm_i915_private *dev_priv, |
1008 | struct bdb_header *bdb) |
||
1009 | { |
||
1010 | struct bdb_general_definitions *p_defs; |
||
4560 | Serge | 1011 | union child_device_config *p_child, *child_dev_ptr; |
2351 | Serge | 1012 | int i, child_device_num, count; |
1013 | u16 block_size; |
||
1014 | |||
1015 | p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS); |
||
1016 | if (!p_defs) { |
||
1017 | DRM_DEBUG_KMS("No general definition block is found, no devices defined.\n"); |
||
1018 | return; |
||
1019 | } |
||
1020 | /* judge whether the size of child device meets the requirements. |
||
1021 | * If the child device size obtained from general definition block |
||
1022 | * is different with sizeof(struct child_device_config), skip the |
||
1023 | * parsing of sdvo device info |
||
1024 | */ |
||
1025 | if (p_defs->child_dev_size != sizeof(*p_child)) { |
||
1026 | /* different child dev size . Ignore it */ |
||
1027 | DRM_DEBUG_KMS("different child size is found. Invalid.\n"); |
||
1028 | return; |
||
1029 | } |
||
1030 | /* get the block size of general definitions */ |
||
1031 | block_size = get_blocksize(p_defs); |
||
1032 | /* get the number of child device */ |
||
1033 | child_device_num = (block_size - sizeof(*p_defs)) / |
||
1034 | sizeof(*p_child); |
||
1035 | count = 0; |
||
1036 | /* get the number of child device that is present */ |
||
1037 | for (i = 0; i < child_device_num; i++) { |
||
1038 | p_child = &(p_defs->devices[i]); |
||
4560 | Serge | 1039 | if (!p_child->common.device_type) { |
2351 | Serge | 1040 | /* skip the device block if device type is invalid */ |
1041 | continue; |
||
1042 | } |
||
1043 | count++; |
||
1044 | } |
||
1045 | if (!count) { |
||
1046 | DRM_DEBUG_KMS("no child dev is parsed from VBT\n"); |
||
1047 | return; |
||
1048 | } |
||
4104 | Serge | 1049 | dev_priv->vbt.child_dev = kcalloc(count, sizeof(*p_child), GFP_KERNEL); |
1050 | if (!dev_priv->vbt.child_dev) { |
||
2351 | Serge | 1051 | DRM_DEBUG_KMS("No memory space for child device\n"); |
1052 | return; |
||
1053 | } |
||
1054 | |||
4104 | Serge | 1055 | dev_priv->vbt.child_dev_num = count; |
2351 | Serge | 1056 | count = 0; |
1057 | for (i = 0; i < child_device_num; i++) { |
||
1058 | p_child = &(p_defs->devices[i]); |
||
4560 | Serge | 1059 | if (!p_child->common.device_type) { |
2351 | Serge | 1060 | /* skip the device block if device type is invalid */ |
1061 | continue; |
||
1062 | } |
||
5060 | serge | 1063 | |
1064 | if (p_child->common.dvo_port >= DVO_PORT_MIPIA |
||
1065 | && p_child->common.dvo_port <= DVO_PORT_MIPID |
||
1066 | &&p_child->common.device_type & DEVICE_TYPE_MIPI_OUTPUT) { |
||
1067 | DRM_DEBUG_KMS("Found MIPI as LFP\n"); |
||
1068 | dev_priv->vbt.has_mipi = 1; |
||
1069 | dev_priv->vbt.dsi.port = p_child->common.dvo_port; |
||
1070 | } |
||
1071 | |||
4104 | Serge | 1072 | child_dev_ptr = dev_priv->vbt.child_dev + count; |
2351 | Serge | 1073 | count++; |
1074 | memcpy((void *)child_dev_ptr, (void *)p_child, |
||
1075 | sizeof(*p_child)); |
||
1076 | } |
||
1077 | return; |
||
1078 | } |
||
1079 | |||
1080 | static void |
||
1081 | init_vbt_defaults(struct drm_i915_private *dev_priv) |
||
1082 | { |
||
1083 | struct drm_device *dev = dev_priv->dev; |
||
4560 | Serge | 1084 | enum port port; |
2351 | Serge | 1085 | |
4104 | Serge | 1086 | dev_priv->vbt.crt_ddc_pin = GMBUS_PORT_VGADDC; |
2351 | Serge | 1087 | |
5060 | serge | 1088 | /* Default to having backlight */ |
1089 | dev_priv->vbt.backlight.present = true; |
||
1090 | |||
2351 | Serge | 1091 | /* LFP panel data */ |
4104 | Serge | 1092 | dev_priv->vbt.lvds_dither = 1; |
1093 | dev_priv->vbt.lvds_vbt = 0; |
||
2351 | Serge | 1094 | |
1095 | /* SDVO panel data */ |
||
4104 | Serge | 1096 | dev_priv->vbt.sdvo_lvds_vbt_mode = NULL; |
2351 | Serge | 1097 | |
1098 | /* general features */ |
||
4104 | Serge | 1099 | dev_priv->vbt.int_tv_support = 1; |
1100 | dev_priv->vbt.int_crt_support = 1; |
||
2351 | Serge | 1101 | |
1102 | /* Default to using SSC */ |
||
4104 | Serge | 1103 | dev_priv->vbt.lvds_use_ssc = 1; |
4560 | Serge | 1104 | /* |
1105 | * Core/SandyBridge/IvyBridge use alternative (120MHz) reference |
||
1106 | * clock for LVDS. |
||
1107 | */ |
||
1108 | dev_priv->vbt.lvds_ssc_freq = intel_bios_ssc_frequency(dev, |
||
1109 | !HAS_PCH_SPLIT(dev)); |
||
1110 | DRM_DEBUG_KMS("Set default to SSC at %d kHz\n", dev_priv->vbt.lvds_ssc_freq); |
||
1111 | |||
1112 | for (port = PORT_A; port < I915_MAX_PORTS; port++) { |
||
1113 | struct ddi_vbt_port_info *info = |
||
1114 | &dev_priv->vbt.ddi_port_info[port]; |
||
1115 | |||
1116 | /* Recommended BSpec default: 800mV 0dB. */ |
||
1117 | info->hdmi_level_shift = 6; |
||
1118 | |||
1119 | info->supports_dvi = (port != PORT_A && port != PORT_E); |
||
1120 | info->supports_hdmi = info->supports_dvi; |
||
1121 | info->supports_dp = (port != PORT_E); |
||
1122 | } |
||
2351 | Serge | 1123 | } |
1124 | |||
5060 | serge | 1125 | static struct bdb_header *validate_vbt(char *base, size_t size, |
1126 | struct vbt_header *vbt, |
||
1127 | const char *source) |
||
1128 | { |
||
1129 | size_t offset; |
||
1130 | struct bdb_header *bdb; |
||
3120 | serge | 1131 | |
5060 | serge | 1132 | if (vbt == NULL) { |
1133 | DRM_DEBUG_DRIVER("VBT signature missing\n"); |
||
1134 | return NULL; |
||
1135 | } |
||
1136 | |||
1137 | offset = (char *)vbt - base; |
||
1138 | if (offset + sizeof(struct vbt_header) > size) { |
||
1139 | DRM_DEBUG_DRIVER("VBT header incomplete\n"); |
||
1140 | return NULL; |
||
1141 | } |
||
1142 | |||
1143 | if (memcmp(vbt->signature, "$VBT", 4)) { |
||
1144 | DRM_DEBUG_DRIVER("VBT invalid signature\n"); |
||
1145 | return NULL; |
||
1146 | } |
||
1147 | |||
1148 | offset += vbt->bdb_offset; |
||
1149 | if (offset + sizeof(struct bdb_header) > size) { |
||
1150 | DRM_DEBUG_DRIVER("BDB header incomplete\n"); |
||
1151 | return NULL; |
||
1152 | } |
||
1153 | |||
1154 | bdb = (struct bdb_header *)(base + offset); |
||
1155 | if (offset + bdb->bdb_size > size) { |
||
1156 | DRM_DEBUG_DRIVER("BDB incomplete\n"); |
||
1157 | return NULL; |
||
1158 | } |
||
1159 | |||
1160 | DRM_DEBUG_KMS("Using VBT from %s: %20s\n", |
||
1161 | source, vbt->signature); |
||
1162 | return bdb; |
||
1163 | } |
||
1164 | |||
2351 | Serge | 1165 | /** |
1166 | * intel_parse_bios - find VBT and initialize settings from the BIOS |
||
1167 | * @dev: DRM device |
||
1168 | * |
||
1169 | * Loads the Video BIOS and checks that the VBT exists. Sets scratch registers |
||
1170 | * to appropriate values. |
||
1171 | * |
||
1172 | * Returns 0 on success, nonzero on failure. |
||
1173 | */ |
||
3031 | serge | 1174 | int |
2351 | Serge | 1175 | intel_parse_bios(struct drm_device *dev) |
1176 | { |
||
1177 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
1178 | struct pci_dev *pdev = dev->pdev; |
||
1179 | struct bdb_header *bdb = NULL; |
||
1180 | u8 __iomem *bios = NULL; |
||
1181 | |||
3746 | Serge | 1182 | if (HAS_PCH_NOP(dev)) |
1183 | return -ENODEV; |
||
1184 | |||
2351 | Serge | 1185 | init_vbt_defaults(dev_priv); |
1186 | |||
1187 | /* XXX Should this validation be moved to intel_opregion.c? */ |
||
5060 | serge | 1188 | if (dev_priv->opregion.vbt) |
1189 | bdb = validate_vbt((char *)dev_priv->opregion.header, OPREGION_SIZE, |
||
1190 | (struct vbt_header *)dev_priv->opregion.vbt, |
||
1191 | "OpRegion"); |
||
2351 | Serge | 1192 | |
1193 | if (bdb == NULL) { |
||
5060 | serge | 1194 | size_t i, size; |
2351 | Serge | 1195 | |
2360 | Serge | 1196 | bios = pci_map_rom(pdev, &size); |
2351 | Serge | 1197 | if (!bios) |
1198 | return -1; |
||
1199 | |||
1200 | /* Scour memory looking for the VBT signature */ |
||
1201 | for (i = 0; i + 4 < size; i++) { |
||
5060 | serge | 1202 | if (memcmp(bios + i, "$VBT", 4) == 0) { |
1203 | bdb = validate_vbt(bios, size, |
||
1204 | (struct vbt_header *)(bios + i), |
||
1205 | "PCI ROM"); |
||
2351 | Serge | 1206 | break; |
1207 | } |
||
1208 | } |
||
1209 | |||
5060 | serge | 1210 | if (!bdb) { |
2351 | Serge | 1211 | pci_unmap_rom(pdev, bios); |
1212 | return -1; |
||
1213 | } |
||
1214 | } |
||
1215 | |||
1216 | /* Grab useful general definitions */ |
||
1217 | parse_general_features(dev_priv, bdb); |
||
1218 | parse_general_definitions(dev_priv, bdb); |
||
1219 | parse_lfp_panel_data(dev_priv, bdb); |
||
4560 | Serge | 1220 | parse_lfp_backlight(dev_priv, bdb); |
2351 | Serge | 1221 | parse_sdvo_panel_data(dev_priv, bdb); |
1222 | parse_sdvo_device_mapping(dev_priv, bdb); |
||
1223 | parse_device_mapping(dev_priv, bdb); |
||
1224 | parse_driver_features(dev_priv, bdb); |
||
1225 | parse_edp(dev_priv, bdb); |
||
4560 | Serge | 1226 | parse_mipi(dev_priv, bdb); |
1227 | parse_ddi_ports(dev_priv, bdb); |
||
2351 | Serge | 1228 | |
1229 | if (bios) |
||
1230 | pci_unmap_rom(pdev, bios); |
||
1231 | |||
1232 | return 0; |
||
1233 | } |
||
1234 | |||
1235 | /* Ensure that vital registers have been initialised, even if the BIOS |
||
1236 | * is absent or just failing to do its job. |
||
1237 | */ |
||
1238 | void intel_setup_bios(struct drm_device *dev) |
||
1239 | { |
||
1240 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
1241 | |||
1242 | /* Set the Panel Power On/Off timings if uninitialized. */ |
||
3243 | Serge | 1243 | if (!HAS_PCH_SPLIT(dev) && |
1244 | I915_READ(PP_ON_DELAYS) == 0 && I915_READ(PP_OFF_DELAYS) == 0) { |
||
2351 | Serge | 1245 | /* Set T2 to 40ms and T5 to 200ms */ |
1246 | I915_WRITE(PP_ON_DELAYS, 0x019007d0); |
||
1247 | |||
1248 | /* Set T3 to 35ms and Tx to 200ms */ |
||
1249 | I915_WRITE(PP_OFF_DELAYS, 0x015e07d0); |
||
1250 | } |
||
1251 | }>>=>>>>>>>>>>>>>>>>>>>>><>><>><>><>><>> |