Rev 6937 | 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 | */ |
||
6937 | serge | 27 | |
5097 | serge | 28 | #include |
5060 | serge | 29 | #include |
3031 | serge | 30 | #include |
2351 | Serge | 31 | #include "i915_drv.h" |
32 | #include "intel_bios.h" |
||
33 | |||
7144 | serge | 34 | /** |
35 | * DOC: Video BIOS Table (VBT) |
||
36 | * |
||
37 | * The Video BIOS Table, or VBT, provides platform and board specific |
||
38 | * configuration information to the driver that is not discoverable or available |
||
39 | * through other means. The configuration is mostly related to display |
||
40 | * hardware. The VBT is available via the ACPI OpRegion or, on older systems, in |
||
41 | * the PCI ROM. |
||
42 | * |
||
43 | * The VBT consists of a VBT Header (defined as &struct vbt_header), a BDB |
||
44 | * Header (&struct bdb_header), and a number of BIOS Data Blocks (BDB) that |
||
45 | * contain the actual configuration information. The VBT Header, and thus the |
||
46 | * VBT, begins with "$VBT" signature. The VBT Header contains the offset of the |
||
47 | * BDB Header. The data blocks are concatenated after the BDB Header. The data |
||
48 | * blocks have a 1-byte Block ID, 2-byte Block Size, and Block Size bytes of |
||
49 | * data. (Block 53, the MIPI Sequence Block is an exception.) |
||
50 | * |
||
51 | * The driver parses the VBT during load. The relevant information is stored in |
||
52 | * driver private data for ease of use, and the actual VBT is not read after |
||
53 | * that. |
||
54 | */ |
||
55 | |||
2351 | Serge | 56 | #define SLAVE_ADDR1 0x70 |
57 | #define SLAVE_ADDR2 0x72 |
||
58 | |||
59 | static int panel_type; |
||
60 | |||
7144 | serge | 61 | /* Get BDB block size given a pointer to Block ID. */ |
62 | static u32 _get_blocksize(const u8 *block_base) |
||
63 | { |
||
64 | /* The MIPI Sequence Block v3+ has a separate size field. */ |
||
65 | if (*block_base == BDB_MIPI_SEQUENCE && *(block_base + 3) >= 3) |
||
66 | return *((const u32 *)(block_base + 4)); |
||
67 | else |
||
68 | return *((const u16 *)(block_base + 1)); |
||
69 | } |
||
70 | |||
71 | /* Get BDB block size give a pointer to data after Block ID and Block Size. */ |
||
72 | static u32 get_blocksize(const void *block_data) |
||
73 | { |
||
74 | return _get_blocksize(block_data - 3); |
||
75 | } |
||
76 | |||
6084 | serge | 77 | static const void * |
78 | find_section(const void *_bdb, int section_id) |
||
2351 | Serge | 79 | { |
6084 | serge | 80 | const struct bdb_header *bdb = _bdb; |
81 | const u8 *base = _bdb; |
||
2351 | Serge | 82 | int index = 0; |
6084 | serge | 83 | u32 total, current_size; |
2351 | Serge | 84 | u8 current_id; |
85 | |||
86 | /* skip to first section */ |
||
87 | index += bdb->header_size; |
||
88 | total = bdb->bdb_size; |
||
89 | |||
90 | /* walk the sections looking for section_id */ |
||
5060 | serge | 91 | while (index + 3 < total) { |
2351 | Serge | 92 | current_id = *(base + index); |
7144 | serge | 93 | current_size = _get_blocksize(base + index); |
94 | index += 3; |
||
5060 | serge | 95 | |
96 | if (index + current_size > total) |
||
97 | return NULL; |
||
98 | |||
2351 | Serge | 99 | if (current_id == section_id) |
100 | return base + index; |
||
5060 | serge | 101 | |
2351 | Serge | 102 | index += current_size; |
103 | } |
||
104 | |||
105 | return NULL; |
||
106 | } |
||
107 | |||
108 | static void |
||
109 | fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode, |
||
110 | const struct lvds_dvo_timing *dvo_timing) |
||
111 | { |
||
112 | panel_fixed_mode->hdisplay = (dvo_timing->hactive_hi << 8) | |
||
113 | dvo_timing->hactive_lo; |
||
114 | panel_fixed_mode->hsync_start = panel_fixed_mode->hdisplay + |
||
115 | ((dvo_timing->hsync_off_hi << 8) | dvo_timing->hsync_off_lo); |
||
116 | panel_fixed_mode->hsync_end = panel_fixed_mode->hsync_start + |
||
117 | dvo_timing->hsync_pulse_width; |
||
118 | panel_fixed_mode->htotal = panel_fixed_mode->hdisplay + |
||
119 | ((dvo_timing->hblank_hi << 8) | dvo_timing->hblank_lo); |
||
120 | |||
121 | panel_fixed_mode->vdisplay = (dvo_timing->vactive_hi << 8) | |
||
122 | dvo_timing->vactive_lo; |
||
123 | panel_fixed_mode->vsync_start = panel_fixed_mode->vdisplay + |
||
124 | dvo_timing->vsync_off; |
||
125 | panel_fixed_mode->vsync_end = panel_fixed_mode->vsync_start + |
||
126 | dvo_timing->vsync_pulse_width; |
||
127 | panel_fixed_mode->vtotal = panel_fixed_mode->vdisplay + |
||
128 | ((dvo_timing->vblank_hi << 8) | dvo_timing->vblank_lo); |
||
129 | panel_fixed_mode->clock = dvo_timing->clock * 10; |
||
130 | panel_fixed_mode->type = DRM_MODE_TYPE_PREFERRED; |
||
131 | |||
132 | if (dvo_timing->hsync_positive) |
||
133 | panel_fixed_mode->flags |= DRM_MODE_FLAG_PHSYNC; |
||
134 | else |
||
135 | panel_fixed_mode->flags |= DRM_MODE_FLAG_NHSYNC; |
||
136 | |||
137 | if (dvo_timing->vsync_positive) |
||
138 | panel_fixed_mode->flags |= DRM_MODE_FLAG_PVSYNC; |
||
139 | else |
||
140 | panel_fixed_mode->flags |= DRM_MODE_FLAG_NVSYNC; |
||
141 | |||
142 | /* Some VBTs have bogus h/vtotal values */ |
||
143 | if (panel_fixed_mode->hsync_end > panel_fixed_mode->htotal) |
||
144 | panel_fixed_mode->htotal = panel_fixed_mode->hsync_end + 1; |
||
145 | if (panel_fixed_mode->vsync_end > panel_fixed_mode->vtotal) |
||
146 | panel_fixed_mode->vtotal = panel_fixed_mode->vsync_end + 1; |
||
147 | |||
148 | drm_mode_set_name(panel_fixed_mode); |
||
149 | } |
||
150 | |||
151 | static const struct lvds_dvo_timing * |
||
152 | get_lvds_dvo_timing(const struct bdb_lvds_lfp_data *lvds_lfp_data, |
||
153 | const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs, |
||
154 | int index) |
||
155 | { |
||
156 | /* |
||
157 | * the size of fp_timing varies on the different platform. |
||
158 | * So calculate the DVO timing relative offset in LVDS data |
||
159 | * entry to get the DVO timing entry |
||
160 | */ |
||
161 | |||
162 | int lfp_data_size = |
||
163 | lvds_lfp_data_ptrs->ptr[1].dvo_timing_offset - |
||
164 | lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset; |
||
165 | int dvo_timing_offset = |
||
166 | lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset - |
||
167 | lvds_lfp_data_ptrs->ptr[0].fp_timing_offset; |
||
168 | char *entry = (char *)lvds_lfp_data->data + lfp_data_size * index; |
||
169 | |||
170 | return (struct lvds_dvo_timing *)(entry + dvo_timing_offset); |
||
171 | } |
||
172 | |||
3031 | serge | 173 | /* get lvds_fp_timing entry |
174 | * this function may return NULL if the corresponding entry is invalid |
||
175 | */ |
||
176 | static const struct lvds_fp_timing * |
||
177 | get_lvds_fp_timing(const struct bdb_header *bdb, |
||
178 | const struct bdb_lvds_lfp_data *data, |
||
179 | const struct bdb_lvds_lfp_data_ptrs *ptrs, |
||
180 | int index) |
||
181 | { |
||
182 | size_t data_ofs = (const u8 *)data - (const u8 *)bdb; |
||
183 | u16 data_size = ((const u16 *)data)[-1]; /* stored in header */ |
||
184 | size_t ofs; |
||
185 | |||
186 | if (index >= ARRAY_SIZE(ptrs->ptr)) |
||
187 | return NULL; |
||
188 | ofs = ptrs->ptr[index].fp_timing_offset; |
||
189 | if (ofs < data_ofs || |
||
190 | ofs + sizeof(struct lvds_fp_timing) > data_ofs + data_size) |
||
191 | return NULL; |
||
192 | return (const struct lvds_fp_timing *)((const u8 *)bdb + ofs); |
||
193 | } |
||
194 | |||
2351 | Serge | 195 | /* Try to find integrated panel data */ |
196 | static void |
||
197 | parse_lfp_panel_data(struct drm_i915_private *dev_priv, |
||
6084 | serge | 198 | const struct bdb_header *bdb) |
2351 | Serge | 199 | { |
200 | const struct bdb_lvds_options *lvds_options; |
||
201 | const struct bdb_lvds_lfp_data *lvds_lfp_data; |
||
202 | const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs; |
||
203 | const struct lvds_dvo_timing *panel_dvo_timing; |
||
3031 | serge | 204 | const struct lvds_fp_timing *fp_timing; |
2351 | Serge | 205 | struct drm_display_mode *panel_fixed_mode; |
6084 | serge | 206 | int drrs_mode; |
2351 | Serge | 207 | |
208 | lvds_options = find_section(bdb, BDB_LVDS_OPTIONS); |
||
209 | if (!lvds_options) |
||
210 | return; |
||
211 | |||
4104 | Serge | 212 | dev_priv->vbt.lvds_dither = lvds_options->pixel_dither; |
2351 | Serge | 213 | if (lvds_options->panel_type == 0xff) |
214 | return; |
||
215 | |||
216 | panel_type = lvds_options->panel_type; |
||
217 | |||
5060 | serge | 218 | drrs_mode = (lvds_options->dps_panel_type_bits |
219 | >> (panel_type * 2)) & MODE_MASK; |
||
220 | /* |
||
221 | * VBT has static DRRS = 0 and seamless DRRS = 2. |
||
222 | * The below piece of code is required to adjust vbt.drrs_type |
||
223 | * to match the enum drrs_support_type. |
||
224 | */ |
||
225 | switch (drrs_mode) { |
||
226 | case 0: |
||
227 | dev_priv->vbt.drrs_type = STATIC_DRRS_SUPPORT; |
||
228 | DRM_DEBUG_KMS("DRRS supported mode is static\n"); |
||
229 | break; |
||
230 | case 2: |
||
231 | dev_priv->vbt.drrs_type = SEAMLESS_DRRS_SUPPORT; |
||
232 | DRM_DEBUG_KMS("DRRS supported mode is seamless\n"); |
||
233 | break; |
||
234 | default: |
||
235 | dev_priv->vbt.drrs_type = DRRS_NOT_SUPPORTED; |
||
236 | DRM_DEBUG_KMS("DRRS not supported (VBT input)\n"); |
||
237 | break; |
||
238 | } |
||
239 | |||
2351 | Serge | 240 | lvds_lfp_data = find_section(bdb, BDB_LVDS_LFP_DATA); |
241 | if (!lvds_lfp_data) |
||
242 | return; |
||
243 | |||
244 | lvds_lfp_data_ptrs = find_section(bdb, BDB_LVDS_LFP_DATA_PTRS); |
||
245 | if (!lvds_lfp_data_ptrs) |
||
246 | return; |
||
247 | |||
4104 | Serge | 248 | dev_priv->vbt.lvds_vbt = 1; |
2351 | Serge | 249 | |
250 | panel_dvo_timing = get_lvds_dvo_timing(lvds_lfp_data, |
||
251 | lvds_lfp_data_ptrs, |
||
252 | lvds_options->panel_type); |
||
253 | |||
254 | panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL); |
||
255 | if (!panel_fixed_mode) |
||
256 | return; |
||
257 | |||
258 | fill_detail_timing_data(panel_fixed_mode, panel_dvo_timing); |
||
259 | |||
4104 | Serge | 260 | dev_priv->vbt.lfp_lvds_vbt_mode = panel_fixed_mode; |
2351 | Serge | 261 | |
262 | DRM_DEBUG_KMS("Found panel mode in BIOS VBT tables:\n"); |
||
263 | drm_mode_debug_printmodeline(panel_fixed_mode); |
||
264 | |||
3031 | serge | 265 | fp_timing = get_lvds_fp_timing(bdb, lvds_lfp_data, |
266 | lvds_lfp_data_ptrs, |
||
267 | lvds_options->panel_type); |
||
268 | if (fp_timing) { |
||
269 | /* check the resolution, just to be sure */ |
||
270 | if (fp_timing->x_res == panel_fixed_mode->hdisplay && |
||
271 | fp_timing->y_res == panel_fixed_mode->vdisplay) { |
||
4104 | Serge | 272 | dev_priv->vbt.bios_lvds_val = fp_timing->lvds_reg_val; |
3031 | serge | 273 | DRM_DEBUG_KMS("VBT initial LVDS value %x\n", |
4104 | Serge | 274 | dev_priv->vbt.bios_lvds_val); |
3031 | serge | 275 | } |
276 | } |
||
2351 | Serge | 277 | } |
278 | |||
4560 | Serge | 279 | static void |
6084 | serge | 280 | parse_lfp_backlight(struct drm_i915_private *dev_priv, |
281 | const struct bdb_header *bdb) |
||
4560 | Serge | 282 | { |
283 | const struct bdb_lfp_backlight_data *backlight_data; |
||
284 | const struct bdb_lfp_backlight_data_entry *entry; |
||
285 | |||
286 | backlight_data = find_section(bdb, BDB_LVDS_BACKLIGHT); |
||
287 | if (!backlight_data) |
||
288 | return; |
||
289 | |||
290 | if (backlight_data->entry_size != sizeof(backlight_data->data[0])) { |
||
291 | DRM_DEBUG_KMS("Unsupported backlight data entry size %u\n", |
||
292 | backlight_data->entry_size); |
||
293 | return; |
||
294 | } |
||
295 | |||
296 | entry = &backlight_data->data[panel_type]; |
||
297 | |||
5060 | serge | 298 | dev_priv->vbt.backlight.present = entry->type == BDB_BACKLIGHT_TYPE_PWM; |
299 | if (!dev_priv->vbt.backlight.present) { |
||
300 | DRM_DEBUG_KMS("PWM backlight not present in VBT (type %u)\n", |
||
301 | entry->type); |
||
302 | return; |
||
303 | } |
||
304 | |||
4560 | Serge | 305 | dev_priv->vbt.backlight.pwm_freq_hz = entry->pwm_freq_hz; |
306 | dev_priv->vbt.backlight.active_low_pwm = entry->active_low_pwm; |
||
5060 | serge | 307 | dev_priv->vbt.backlight.min_brightness = entry->min_brightness; |
4560 | Serge | 308 | DRM_DEBUG_KMS("VBT backlight PWM modulation frequency %u Hz, " |
309 | "active %s, min brightness %u, level %u\n", |
||
310 | dev_priv->vbt.backlight.pwm_freq_hz, |
||
311 | dev_priv->vbt.backlight.active_low_pwm ? "low" : "high", |
||
5060 | serge | 312 | dev_priv->vbt.backlight.min_brightness, |
4560 | Serge | 313 | backlight_data->level[panel_type]); |
314 | } |
||
315 | |||
2351 | Serge | 316 | /* Try to find sdvo panel data */ |
317 | static void |
||
318 | parse_sdvo_panel_data(struct drm_i915_private *dev_priv, |
||
6084 | serge | 319 | const struct bdb_header *bdb) |
2351 | Serge | 320 | { |
6084 | serge | 321 | const struct lvds_dvo_timing *dvo_timing; |
2351 | Serge | 322 | struct drm_display_mode *panel_fixed_mode; |
323 | int index; |
||
324 | |||
5060 | serge | 325 | index = i915.vbt_sdvo_panel_type; |
3031 | serge | 326 | if (index == -2) { |
327 | DRM_DEBUG_KMS("Ignore SDVO panel mode from BIOS VBT tables.\n"); |
||
328 | return; |
||
329 | } |
||
330 | |||
2351 | Serge | 331 | if (index == -1) { |
6084 | serge | 332 | const struct bdb_sdvo_lvds_options *sdvo_lvds_options; |
2351 | Serge | 333 | |
334 | sdvo_lvds_options = find_section(bdb, BDB_SDVO_LVDS_OPTIONS); |
||
335 | if (!sdvo_lvds_options) |
||
336 | return; |
||
337 | |||
338 | index = sdvo_lvds_options->panel_type; |
||
339 | } |
||
340 | |||
341 | dvo_timing = find_section(bdb, BDB_SDVO_PANEL_DTDS); |
||
342 | if (!dvo_timing) |
||
343 | return; |
||
344 | |||
345 | panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL); |
||
346 | if (!panel_fixed_mode) |
||
347 | return; |
||
348 | |||
349 | fill_detail_timing_data(panel_fixed_mode, dvo_timing + index); |
||
350 | |||
4104 | Serge | 351 | dev_priv->vbt.sdvo_lvds_vbt_mode = panel_fixed_mode; |
2351 | Serge | 352 | |
353 | DRM_DEBUG_KMS("Found SDVO panel mode in BIOS VBT tables:\n"); |
||
354 | drm_mode_debug_printmodeline(panel_fixed_mode); |
||
355 | } |
||
356 | |||
6937 | serge | 357 | static int intel_bios_ssc_frequency(struct drm_i915_private *dev_priv, |
2351 | Serge | 358 | bool alternate) |
359 | { |
||
6937 | serge | 360 | switch (INTEL_INFO(dev_priv)->gen) { |
2351 | Serge | 361 | case 2: |
4560 | Serge | 362 | return alternate ? 66667 : 48000; |
2351 | Serge | 363 | case 3: |
364 | case 4: |
||
4560 | Serge | 365 | return alternate ? 100000 : 96000; |
2351 | Serge | 366 | default: |
4560 | Serge | 367 | return alternate ? 100000 : 120000; |
2351 | Serge | 368 | } |
369 | } |
||
370 | |||
371 | static void |
||
372 | parse_general_features(struct drm_i915_private *dev_priv, |
||
6084 | serge | 373 | const struct bdb_header *bdb) |
2351 | Serge | 374 | { |
6084 | serge | 375 | const struct bdb_general_features *general; |
2351 | Serge | 376 | |
377 | general = find_section(bdb, BDB_GENERAL_FEATURES); |
||
6937 | serge | 378 | if (!general) |
379 | return; |
||
380 | |||
7144 | serge | 381 | dev_priv->vbt.int_tv_support = general->int_tv_support; |
6937 | serge | 382 | /* int_crt_support can't be trusted on earlier platforms */ |
383 | if (bdb->version >= 155 && |
||
384 | (HAS_DDI(dev_priv) || IS_VALLEYVIEW(dev_priv))) |
||
4104 | Serge | 385 | dev_priv->vbt.int_crt_support = general->int_crt_support; |
7144 | serge | 386 | dev_priv->vbt.lvds_use_ssc = general->enable_ssc; |
387 | dev_priv->vbt.lvds_ssc_freq = |
||
6937 | serge | 388 | intel_bios_ssc_frequency(dev_priv, general->ssc_freq); |
7144 | serge | 389 | dev_priv->vbt.display_clock_mode = general->display_clock_mode; |
390 | dev_priv->vbt.fdi_rx_polarity_inverted = general->fdi_rx_polarity_inverted; |
||
391 | 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", |
||
392 | dev_priv->vbt.int_tv_support, |
||
393 | dev_priv->vbt.int_crt_support, |
||
394 | dev_priv->vbt.lvds_use_ssc, |
||
395 | dev_priv->vbt.lvds_ssc_freq, |
||
396 | dev_priv->vbt.display_clock_mode, |
||
397 | dev_priv->vbt.fdi_rx_polarity_inverted); |
||
398 | } |
||
2351 | Serge | 399 | |
400 | static void |
||
401 | parse_general_definitions(struct drm_i915_private *dev_priv, |
||
6084 | serge | 402 | const struct bdb_header *bdb) |
2351 | Serge | 403 | { |
6084 | serge | 404 | const struct bdb_general_definitions *general; |
2351 | Serge | 405 | |
406 | general = find_section(bdb, BDB_GENERAL_DEFINITIONS); |
||
407 | if (general) { |
||
408 | u16 block_size = get_blocksize(general); |
||
409 | if (block_size >= sizeof(*general)) { |
||
410 | int bus_pin = general->crt_ddc_gmbus_pin; |
||
411 | DRM_DEBUG_KMS("crt_ddc_bus_pin: %d\n", bus_pin); |
||
6084 | serge | 412 | if (intel_gmbus_is_valid_pin(dev_priv, bus_pin)) |
4104 | Serge | 413 | dev_priv->vbt.crt_ddc_pin = bus_pin; |
2351 | Serge | 414 | } else { |
415 | DRM_DEBUG_KMS("BDB_GD too small (%d). Invalid.\n", |
||
6084 | serge | 416 | block_size); |
2351 | Serge | 417 | } |
418 | } |
||
419 | } |
||
420 | |||
6084 | serge | 421 | static const union child_device_config * |
422 | child_device_ptr(const struct bdb_general_definitions *p_defs, int i) |
||
423 | { |
||
424 | return (const void *) &p_defs->devices[i * p_defs->child_dev_size]; |
||
425 | } |
||
426 | |||
2351 | Serge | 427 | static void |
428 | parse_sdvo_device_mapping(struct drm_i915_private *dev_priv, |
||
6084 | serge | 429 | const struct bdb_header *bdb) |
2351 | Serge | 430 | { |
431 | struct sdvo_device_mapping *p_mapping; |
||
6084 | serge | 432 | const struct bdb_general_definitions *p_defs; |
433 | const struct old_child_dev_config *child; /* legacy */ |
||
2351 | Serge | 434 | int i, child_device_num, count; |
435 | u16 block_size; |
||
436 | |||
437 | p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS); |
||
438 | if (!p_defs) { |
||
439 | DRM_DEBUG_KMS("No general definition block is found, unable to construct sdvo mapping.\n"); |
||
440 | return; |
||
441 | } |
||
6084 | serge | 442 | |
443 | /* |
||
444 | * Only parse SDVO mappings when the general definitions block child |
||
445 | * device size matches that of the *legacy* child device config |
||
446 | * struct. Thus, SDVO mapping will be skipped for newer VBT. |
||
2351 | Serge | 447 | */ |
6084 | serge | 448 | if (p_defs->child_dev_size != sizeof(*child)) { |
449 | DRM_DEBUG_KMS("Unsupported child device size for SDVO mapping.\n"); |
||
2351 | Serge | 450 | return; |
451 | } |
||
452 | /* get the block size of general definitions */ |
||
453 | block_size = get_blocksize(p_defs); |
||
454 | /* get the number of child device */ |
||
455 | child_device_num = (block_size - sizeof(*p_defs)) / |
||
6084 | serge | 456 | p_defs->child_dev_size; |
2351 | Serge | 457 | count = 0; |
458 | for (i = 0; i < child_device_num; i++) { |
||
6084 | serge | 459 | child = &child_device_ptr(p_defs, i)->old; |
460 | if (!child->device_type) { |
||
2351 | Serge | 461 | /* skip the device block if device type is invalid */ |
462 | continue; |
||
463 | } |
||
6084 | serge | 464 | if (child->slave_addr != SLAVE_ADDR1 && |
465 | child->slave_addr != SLAVE_ADDR2) { |
||
2351 | Serge | 466 | /* |
467 | * If the slave address is neither 0x70 nor 0x72, |
||
468 | * it is not a SDVO device. Skip it. |
||
469 | */ |
||
470 | continue; |
||
471 | } |
||
6084 | serge | 472 | if (child->dvo_port != DEVICE_PORT_DVOB && |
473 | child->dvo_port != DEVICE_PORT_DVOC) { |
||
2351 | Serge | 474 | /* skip the incorrect SDVO port */ |
475 | DRM_DEBUG_KMS("Incorrect SDVO port. Skip it\n"); |
||
476 | continue; |
||
477 | } |
||
478 | DRM_DEBUG_KMS("the SDVO device with slave addr %2x is found on" |
||
6084 | serge | 479 | " %s port\n", |
480 | child->slave_addr, |
||
481 | (child->dvo_port == DEVICE_PORT_DVOB) ? |
||
482 | "SDVOB" : "SDVOC"); |
||
483 | p_mapping = &(dev_priv->sdvo_mappings[child->dvo_port - 1]); |
||
2351 | Serge | 484 | if (!p_mapping->initialized) { |
6084 | serge | 485 | p_mapping->dvo_port = child->dvo_port; |
486 | p_mapping->slave_addr = child->slave_addr; |
||
487 | p_mapping->dvo_wiring = child->dvo_wiring; |
||
488 | p_mapping->ddc_pin = child->ddc_pin; |
||
489 | p_mapping->i2c_pin = child->i2c_pin; |
||
2351 | Serge | 490 | p_mapping->initialized = 1; |
491 | DRM_DEBUG_KMS("SDVO device: dvo=%x, addr=%x, wiring=%d, ddc_pin=%d, i2c_pin=%d\n", |
||
492 | p_mapping->dvo_port, |
||
493 | p_mapping->slave_addr, |
||
494 | p_mapping->dvo_wiring, |
||
495 | p_mapping->ddc_pin, |
||
496 | p_mapping->i2c_pin); |
||
497 | } else { |
||
498 | DRM_DEBUG_KMS("Maybe one SDVO port is shared by " |
||
499 | "two SDVO device.\n"); |
||
500 | } |
||
6084 | serge | 501 | if (child->slave2_addr) { |
2351 | Serge | 502 | /* Maybe this is a SDVO device with multiple inputs */ |
503 | /* And the mapping info is not added */ |
||
504 | DRM_DEBUG_KMS("there exists the slave2_addr. Maybe this" |
||
505 | " is a SDVO device with multiple inputs.\n"); |
||
506 | } |
||
507 | count++; |
||
508 | } |
||
509 | |||
510 | if (!count) { |
||
511 | /* No SDVO device info is found */ |
||
512 | DRM_DEBUG_KMS("No SDVO device info is found in VBT\n"); |
||
513 | } |
||
514 | return; |
||
515 | } |
||
516 | |||
517 | static void |
||
518 | parse_driver_features(struct drm_i915_private *dev_priv, |
||
6084 | serge | 519 | const struct bdb_header *bdb) |
2351 | Serge | 520 | { |
6084 | serge | 521 | const struct bdb_driver_features *driver; |
2351 | Serge | 522 | |
523 | driver = find_section(bdb, BDB_DRIVER_FEATURES); |
||
524 | if (!driver) |
||
525 | return; |
||
526 | |||
4560 | Serge | 527 | if (driver->lvds_config == BDB_DRIVER_FEATURE_EDP) |
4104 | Serge | 528 | dev_priv->vbt.edp_support = 1; |
2351 | Serge | 529 | |
530 | if (driver->dual_frequency) |
||
531 | dev_priv->render_reclock_avail = true; |
||
5060 | serge | 532 | |
533 | DRM_DEBUG_KMS("DRRS State Enabled:%d\n", driver->drrs_enabled); |
||
534 | /* |
||
535 | * If DRRS is not supported, drrs_type has to be set to 0. |
||
536 | * This is because, VBT is configured in such a way that |
||
537 | * static DRRS is 0 and DRRS not supported is represented by |
||
538 | * driver->drrs_enabled=false |
||
539 | */ |
||
540 | if (!driver->drrs_enabled) |
||
541 | dev_priv->vbt.drrs_type = DRRS_NOT_SUPPORTED; |
||
2351 | Serge | 542 | } |
543 | |||
544 | static void |
||
6084 | serge | 545 | parse_edp(struct drm_i915_private *dev_priv, const struct bdb_header *bdb) |
2351 | Serge | 546 | { |
6084 | serge | 547 | const struct bdb_edp *edp; |
548 | const struct edp_power_seq *edp_pps; |
||
549 | const struct edp_link_params *edp_link_params; |
||
2351 | Serge | 550 | |
551 | edp = find_section(bdb, BDB_EDP); |
||
552 | if (!edp) { |
||
4560 | Serge | 553 | if (dev_priv->vbt.edp_support) |
3120 | serge | 554 | DRM_DEBUG_KMS("No eDP BDB found but eDP panel supported.\n"); |
2351 | Serge | 555 | return; |
556 | } |
||
557 | |||
558 | switch ((edp->color_depth >> (panel_type * 2)) & 3) { |
||
559 | case EDP_18BPP: |
||
4104 | Serge | 560 | dev_priv->vbt.edp_bpp = 18; |
2351 | Serge | 561 | break; |
562 | case EDP_24BPP: |
||
4104 | Serge | 563 | dev_priv->vbt.edp_bpp = 24; |
2351 | Serge | 564 | break; |
565 | case EDP_30BPP: |
||
4104 | Serge | 566 | dev_priv->vbt.edp_bpp = 30; |
2351 | Serge | 567 | break; |
568 | } |
||
569 | |||
570 | /* Get the eDP sequencing and link info */ |
||
571 | edp_pps = &edp->power_seqs[panel_type]; |
||
572 | edp_link_params = &edp->link_params[panel_type]; |
||
573 | |||
4104 | Serge | 574 | dev_priv->vbt.edp_pps = *edp_pps; |
2351 | Serge | 575 | |
5060 | serge | 576 | switch (edp_link_params->rate) { |
577 | case EDP_RATE_1_62: |
||
578 | dev_priv->vbt.edp_rate = DP_LINK_BW_1_62; |
||
579 | break; |
||
580 | case EDP_RATE_2_7: |
||
581 | dev_priv->vbt.edp_rate = DP_LINK_BW_2_7; |
||
582 | break; |
||
583 | default: |
||
584 | DRM_DEBUG_KMS("VBT has unknown eDP link rate value %u\n", |
||
585 | edp_link_params->rate); |
||
586 | break; |
||
587 | } |
||
588 | |||
2351 | Serge | 589 | switch (edp_link_params->lanes) { |
5060 | serge | 590 | case EDP_LANE_1: |
4104 | Serge | 591 | dev_priv->vbt.edp_lanes = 1; |
2351 | Serge | 592 | break; |
5060 | serge | 593 | case EDP_LANE_2: |
4104 | Serge | 594 | dev_priv->vbt.edp_lanes = 2; |
2351 | Serge | 595 | break; |
5060 | serge | 596 | case EDP_LANE_4: |
4104 | Serge | 597 | dev_priv->vbt.edp_lanes = 4; |
2351 | Serge | 598 | break; |
5060 | serge | 599 | default: |
600 | DRM_DEBUG_KMS("VBT has unknown eDP lane count value %u\n", |
||
601 | edp_link_params->lanes); |
||
602 | break; |
||
2351 | Serge | 603 | } |
5060 | serge | 604 | |
2351 | Serge | 605 | switch (edp_link_params->preemphasis) { |
5060 | serge | 606 | case EDP_PREEMPHASIS_NONE: |
5354 | serge | 607 | dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_0; |
2351 | Serge | 608 | break; |
5060 | serge | 609 | case EDP_PREEMPHASIS_3_5dB: |
5354 | serge | 610 | dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_1; |
2351 | Serge | 611 | break; |
5060 | serge | 612 | case EDP_PREEMPHASIS_6dB: |
5354 | serge | 613 | dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_2; |
2351 | Serge | 614 | break; |
5060 | serge | 615 | case EDP_PREEMPHASIS_9_5dB: |
5354 | serge | 616 | dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_3; |
2351 | Serge | 617 | break; |
5060 | serge | 618 | default: |
619 | DRM_DEBUG_KMS("VBT has unknown eDP pre-emphasis value %u\n", |
||
620 | edp_link_params->preemphasis); |
||
621 | break; |
||
2351 | Serge | 622 | } |
5060 | serge | 623 | |
2351 | Serge | 624 | switch (edp_link_params->vswing) { |
5060 | serge | 625 | case EDP_VSWING_0_4V: |
5354 | serge | 626 | dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_0; |
2351 | Serge | 627 | break; |
5060 | serge | 628 | case EDP_VSWING_0_6V: |
5354 | serge | 629 | dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_1; |
2351 | Serge | 630 | break; |
5060 | serge | 631 | case EDP_VSWING_0_8V: |
5354 | serge | 632 | dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_2; |
2351 | Serge | 633 | break; |
5060 | serge | 634 | case EDP_VSWING_1_2V: |
5354 | serge | 635 | dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_3; |
2351 | Serge | 636 | break; |
5060 | serge | 637 | default: |
638 | DRM_DEBUG_KMS("VBT has unknown eDP voltage swing value %u\n", |
||
639 | edp_link_params->vswing); |
||
640 | break; |
||
2351 | Serge | 641 | } |
6084 | serge | 642 | |
643 | if (bdb->version >= 173) { |
||
644 | uint8_t vswing; |
||
645 | |||
646 | /* Don't read from VBT if module parameter has valid value*/ |
||
647 | if (i915.edp_vswing) { |
||
648 | dev_priv->edp_low_vswing = i915.edp_vswing == 1; |
||
649 | } else { |
||
650 | vswing = (edp->edp_vswing_preemph >> (panel_type * 4)) & 0xF; |
||
651 | dev_priv->edp_low_vswing = vswing == 0; |
||
652 | } |
||
653 | } |
||
2351 | Serge | 654 | } |
655 | |||
6084 | serge | 656 | static void |
657 | parse_psr(struct drm_i915_private *dev_priv, const struct bdb_header *bdb) |
||
658 | { |
||
659 | const struct bdb_psr *psr; |
||
660 | const struct psr_table *psr_table; |
||
661 | |||
662 | psr = find_section(bdb, BDB_PSR); |
||
663 | if (!psr) { |
||
664 | DRM_DEBUG_KMS("No PSR BDB found.\n"); |
||
665 | return; |
||
666 | } |
||
667 | |||
668 | psr_table = &psr->psr_table[panel_type]; |
||
669 | |||
670 | dev_priv->vbt.psr.full_link = psr_table->full_link; |
||
671 | dev_priv->vbt.psr.require_aux_wakeup = psr_table->require_aux_to_wakeup; |
||
672 | |||
673 | /* Allowed VBT values goes from 0 to 15 */ |
||
674 | dev_priv->vbt.psr.idle_frames = psr_table->idle_frames < 0 ? 0 : |
||
675 | psr_table->idle_frames > 15 ? 15 : psr_table->idle_frames; |
||
676 | |||
677 | switch (psr_table->lines_to_wait) { |
||
678 | case 0: |
||
679 | dev_priv->vbt.psr.lines_to_wait = PSR_0_LINES_TO_WAIT; |
||
680 | break; |
||
681 | case 1: |
||
682 | dev_priv->vbt.psr.lines_to_wait = PSR_1_LINE_TO_WAIT; |
||
683 | break; |
||
684 | case 2: |
||
685 | dev_priv->vbt.psr.lines_to_wait = PSR_4_LINES_TO_WAIT; |
||
686 | break; |
||
687 | case 3: |
||
688 | dev_priv->vbt.psr.lines_to_wait = PSR_8_LINES_TO_WAIT; |
||
689 | break; |
||
690 | default: |
||
691 | DRM_DEBUG_KMS("VBT has unknown PSR lines to wait %u\n", |
||
692 | psr_table->lines_to_wait); |
||
693 | break; |
||
694 | } |
||
695 | |||
696 | dev_priv->vbt.psr.tp1_wakeup_time = psr_table->tp1_wakeup_time; |
||
697 | dev_priv->vbt.psr.tp2_tp3_wakeup_time = psr_table->tp2_tp3_wakeup_time; |
||
698 | } |
||
699 | |||
2351 | Serge | 700 | static void |
7144 | serge | 701 | parse_mipi_config(struct drm_i915_private *dev_priv, |
702 | const struct bdb_header *bdb) |
||
4560 | Serge | 703 | { |
6084 | serge | 704 | const struct bdb_mipi_config *start; |
705 | const struct mipi_config *config; |
||
706 | const struct mipi_pps_data *pps; |
||
4560 | Serge | 707 | |
5060 | serge | 708 | /* parse MIPI blocks only if LFP type is MIPI */ |
709 | if (!dev_priv->vbt.has_mipi) |
||
4560 | Serge | 710 | return; |
5060 | serge | 711 | |
712 | /* Initialize this to undefined indicating no generic MIPI support */ |
||
713 | dev_priv->vbt.dsi.panel_id = MIPI_DSI_UNDEFINED_PANEL_ID; |
||
714 | |||
715 | /* Block #40 is already parsed and panel_fixed_mode is |
||
716 | * stored in dev_priv->lfp_lvds_vbt_mode |
||
717 | * resuse this when needed |
||
718 | */ |
||
719 | |||
720 | /* Parse #52 for panel index used from panel_type already |
||
721 | * parsed |
||
722 | */ |
||
723 | start = find_section(bdb, BDB_MIPI_CONFIG); |
||
724 | if (!start) { |
||
725 | DRM_DEBUG_KMS("No MIPI config BDB found"); |
||
726 | return; |
||
4560 | Serge | 727 | } |
728 | |||
5060 | serge | 729 | DRM_DEBUG_DRIVER("Found MIPI Config block, panel index = %d\n", |
730 | panel_type); |
||
731 | |||
732 | /* |
||
733 | * get hold of the correct configuration block and pps data as per |
||
734 | * the panel_type as index |
||
735 | */ |
||
736 | config = &start->config[panel_type]; |
||
737 | pps = &start->pps[panel_type]; |
||
738 | |||
739 | /* store as of now full data. Trim when we realise all is not needed */ |
||
740 | dev_priv->vbt.dsi.config = kmemdup(config, sizeof(struct mipi_config), GFP_KERNEL); |
||
741 | if (!dev_priv->vbt.dsi.config) |
||
742 | return; |
||
743 | |||
744 | dev_priv->vbt.dsi.pps = kmemdup(pps, sizeof(struct mipi_pps_data), GFP_KERNEL); |
||
745 | if (!dev_priv->vbt.dsi.pps) { |
||
746 | kfree(dev_priv->vbt.dsi.config); |
||
747 | return; |
||
748 | } |
||
749 | |||
750 | /* We have mandatory mipi config blocks. Initialize as generic panel */ |
||
751 | dev_priv->vbt.dsi.panel_id = MIPI_DSI_GENERIC_PANEL_ID; |
||
7144 | serge | 752 | } |
5060 | serge | 753 | |
7144 | serge | 754 | /* Find the sequence block and size for the given panel. */ |
755 | static const u8 * |
||
756 | find_panel_sequence_block(const struct bdb_mipi_sequence *sequence, |
||
757 | u16 panel_id, u32 *seq_size) |
||
758 | { |
||
759 | u32 total = get_blocksize(sequence); |
||
760 | const u8 *data = &sequence->data[0]; |
||
761 | u8 current_id; |
||
762 | u32 current_size; |
||
763 | int header_size = sequence->version >= 3 ? 5 : 3; |
||
764 | int index = 0; |
||
765 | int i; |
||
766 | |||
767 | /* skip new block size */ |
||
768 | if (sequence->version >= 3) |
||
769 | data += 4; |
||
770 | |||
771 | for (i = 0; i < MAX_MIPI_CONFIGURATIONS && index < total; i++) { |
||
772 | if (index + header_size > total) { |
||
773 | DRM_ERROR("Invalid sequence block (header)\n"); |
||
774 | return NULL; |
||
775 | } |
||
776 | |||
777 | current_id = *(data + index); |
||
778 | if (sequence->version >= 3) |
||
779 | current_size = *((const u32 *)(data + index + 1)); |
||
780 | else |
||
781 | current_size = *((const u16 *)(data + index + 1)); |
||
782 | |||
783 | index += header_size; |
||
784 | |||
785 | if (index + current_size > total) { |
||
786 | DRM_ERROR("Invalid sequence block\n"); |
||
787 | return NULL; |
||
788 | } |
||
789 | |||
790 | if (current_id == panel_id) { |
||
791 | *seq_size = current_size; |
||
792 | return data + index; |
||
793 | } |
||
794 | |||
795 | index += current_size; |
||
5060 | serge | 796 | } |
797 | |||
7144 | serge | 798 | DRM_ERROR("Sequence block detected but no valid configuration\n"); |
799 | |||
800 | return NULL; |
||
801 | } |
||
802 | |||
803 | static int goto_next_sequence(const u8 *data, int index, int total) |
||
804 | { |
||
805 | u16 len; |
||
806 | |||
807 | /* Skip Sequence Byte. */ |
||
808 | for (index = index + 1; index < total; index += len) { |
||
809 | u8 operation_byte = *(data + index); |
||
810 | index++; |
||
811 | |||
812 | switch (operation_byte) { |
||
813 | case MIPI_SEQ_ELEM_END: |
||
814 | return index; |
||
815 | case MIPI_SEQ_ELEM_SEND_PKT: |
||
816 | if (index + 4 > total) |
||
817 | return 0; |
||
818 | |||
819 | len = *((const u16 *)(data + index + 2)) + 4; |
||
820 | break; |
||
821 | case MIPI_SEQ_ELEM_DELAY: |
||
822 | len = 4; |
||
823 | break; |
||
824 | case MIPI_SEQ_ELEM_GPIO: |
||
825 | len = 2; |
||
826 | break; |
||
827 | case MIPI_SEQ_ELEM_I2C: |
||
828 | if (index + 7 > total) |
||
829 | return 0; |
||
830 | len = *(data + index + 6) + 7; |
||
831 | break; |
||
832 | default: |
||
833 | DRM_ERROR("Unknown operation byte\n"); |
||
834 | return 0; |
||
835 | } |
||
6084 | serge | 836 | } |
837 | |||
7144 | serge | 838 | return 0; |
839 | } |
||
5060 | serge | 840 | |
7144 | serge | 841 | static int goto_next_sequence_v3(const u8 *data, int index, int total) |
842 | { |
||
843 | int seq_end; |
||
844 | u16 len; |
||
845 | u32 size_of_sequence; |
||
5060 | serge | 846 | |
847 | /* |
||
7144 | serge | 848 | * Could skip sequence based on Size of Sequence alone, but also do some |
849 | * checking on the structure. |
||
5060 | serge | 850 | */ |
7144 | serge | 851 | if (total < 5) { |
852 | DRM_ERROR("Too small sequence size\n"); |
||
853 | return 0; |
||
854 | } |
||
5060 | serge | 855 | |
7144 | serge | 856 | /* Skip Sequence Byte. */ |
857 | index++; |
||
5060 | serge | 858 | |
859 | /* |
||
7144 | serge | 860 | * Size of Sequence. Excludes the Sequence Byte and the size itself, |
861 | * includes MIPI_SEQ_ELEM_END byte, excludes the final MIPI_SEQ_END |
||
862 | * byte. |
||
5060 | serge | 863 | */ |
7144 | serge | 864 | size_of_sequence = *((const uint32_t *)(data + index)); |
865 | index += 4; |
||
5060 | serge | 866 | |
7144 | serge | 867 | seq_end = index + size_of_sequence; |
868 | if (seq_end > total) { |
||
869 | DRM_ERROR("Invalid sequence size\n"); |
||
870 | return 0; |
||
871 | } |
||
872 | |||
873 | for (; index < total; index += len) { |
||
874 | u8 operation_byte = *(data + index); |
||
875 | index++; |
||
876 | |||
877 | if (operation_byte == MIPI_SEQ_ELEM_END) { |
||
878 | if (index != seq_end) { |
||
879 | DRM_ERROR("Invalid element structure\n"); |
||
880 | return 0; |
||
881 | } |
||
882 | return index; |
||
5060 | serge | 883 | } |
7144 | serge | 884 | |
885 | len = *(data + index); |
||
886 | index++; |
||
887 | |||
888 | /* |
||
889 | * FIXME: Would be nice to check elements like for v1/v2 in |
||
890 | * goto_next_sequence() above. |
||
891 | */ |
||
892 | switch (operation_byte) { |
||
893 | case MIPI_SEQ_ELEM_SEND_PKT: |
||
894 | case MIPI_SEQ_ELEM_DELAY: |
||
895 | case MIPI_SEQ_ELEM_GPIO: |
||
896 | case MIPI_SEQ_ELEM_I2C: |
||
897 | case MIPI_SEQ_ELEM_SPI: |
||
898 | case MIPI_SEQ_ELEM_PMIC: |
||
899 | break; |
||
900 | default: |
||
901 | DRM_ERROR("Unknown operation byte %u\n", |
||
902 | operation_byte); |
||
903 | break; |
||
904 | } |
||
5060 | serge | 905 | } |
906 | |||
7144 | serge | 907 | return 0; |
908 | } |
||
909 | |||
910 | static void |
||
911 | parse_mipi_sequence(struct drm_i915_private *dev_priv, |
||
912 | const struct bdb_header *bdb) |
||
913 | { |
||
914 | const struct bdb_mipi_sequence *sequence; |
||
915 | const u8 *seq_data; |
||
916 | u32 seq_size; |
||
917 | u8 *data; |
||
918 | int index = 0; |
||
919 | |||
920 | /* Only our generic panel driver uses the sequence block. */ |
||
921 | if (dev_priv->vbt.dsi.panel_id != MIPI_DSI_GENERIC_PANEL_ID) |
||
5060 | serge | 922 | return; |
7144 | serge | 923 | |
924 | sequence = find_section(bdb, BDB_MIPI_SEQUENCE); |
||
925 | if (!sequence) { |
||
926 | DRM_DEBUG_KMS("No MIPI Sequence found, parsing complete\n"); |
||
927 | return; |
||
5060 | serge | 928 | } |
929 | |||
7144 | serge | 930 | /* Fail gracefully for forward incompatible sequence block. */ |
931 | if (sequence->version >= 4) { |
||
932 | DRM_ERROR("Unable to parse MIPI Sequence Block v%u\n", |
||
933 | sequence->version); |
||
5060 | serge | 934 | return; |
935 | } |
||
936 | |||
7144 | serge | 937 | DRM_DEBUG_DRIVER("Found MIPI sequence block v%u\n", sequence->version); |
938 | |||
939 | seq_data = find_panel_sequence_block(sequence, panel_type, &seq_size); |
||
940 | if (!seq_data) |
||
5060 | serge | 941 | return; |
942 | |||
7144 | serge | 943 | data = kmemdup(seq_data, seq_size, GFP_KERNEL); |
944 | if (!data) |
||
945 | return; |
||
5060 | serge | 946 | |
7144 | serge | 947 | /* Parse the sequences, store pointers to each sequence. */ |
948 | for (;;) { |
||
949 | u8 seq_id = *(data + index); |
||
950 | if (seq_id == MIPI_SEQ_END) |
||
951 | break; |
||
952 | |||
953 | if (seq_id >= MIPI_SEQ_MAX) { |
||
954 | DRM_ERROR("Unknown sequence %u\n", seq_id); |
||
5060 | serge | 955 | goto err; |
956 | } |
||
957 | |||
7144 | serge | 958 | dev_priv->vbt.dsi.sequence[seq_id] = data + index; |
5060 | serge | 959 | |
7144 | serge | 960 | if (sequence->version >= 3) |
961 | index = goto_next_sequence_v3(data, index, seq_size); |
||
962 | else |
||
963 | index = goto_next_sequence(data, index, seq_size); |
||
964 | if (!index) { |
||
965 | DRM_ERROR("Invalid sequence %u\n", seq_id); |
||
5060 | serge | 966 | goto err; |
967 | } |
||
968 | } |
||
969 | |||
7144 | serge | 970 | dev_priv->vbt.dsi.data = data; |
971 | dev_priv->vbt.dsi.size = seq_size; |
||
972 | dev_priv->vbt.dsi.seq_version = sequence->version; |
||
973 | |||
974 | DRM_DEBUG_DRIVER("MIPI related VBT parsing complete\n"); |
||
5060 | serge | 975 | return; |
7144 | serge | 976 | |
5060 | serge | 977 | err: |
7144 | serge | 978 | kfree(data); |
5060 | serge | 979 | memset(dev_priv->vbt.dsi.sequence, 0, sizeof(dev_priv->vbt.dsi.sequence)); |
4560 | Serge | 980 | } |
981 | |||
6084 | serge | 982 | static u8 translate_iboost(u8 val) |
983 | { |
||
984 | static const u8 mapping[] = { 1, 3, 7 }; /* See VBT spec */ |
||
985 | |||
986 | if (val >= ARRAY_SIZE(mapping)) { |
||
987 | DRM_DEBUG_KMS("Unsupported I_boost value found in VBT (%d), display may not work properly\n", val); |
||
988 | return 0; |
||
989 | } |
||
990 | return mapping[val]; |
||
991 | } |
||
992 | |||
4560 | Serge | 993 | static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port, |
6084 | serge | 994 | const struct bdb_header *bdb) |
4560 | Serge | 995 | { |
996 | union child_device_config *it, *child = NULL; |
||
997 | struct ddi_vbt_port_info *info = &dev_priv->vbt.ddi_port_info[port]; |
||
998 | uint8_t hdmi_level_shift; |
||
999 | int i, j; |
||
1000 | bool is_dvi, is_hdmi, is_dp, is_edp, is_crt; |
||
6084 | serge | 1001 | uint8_t aux_channel, ddc_pin; |
4560 | Serge | 1002 | /* Each DDI port can have more than one value on the "DVO Port" field, |
1003 | * so look for all the possible values for each port and abort if more |
||
1004 | * than one is found. */ |
||
6084 | serge | 1005 | int dvo_ports[][3] = { |
1006 | {DVO_PORT_HDMIA, DVO_PORT_DPA, -1}, |
||
1007 | {DVO_PORT_HDMIB, DVO_PORT_DPB, -1}, |
||
1008 | {DVO_PORT_HDMIC, DVO_PORT_DPC, -1}, |
||
1009 | {DVO_PORT_HDMID, DVO_PORT_DPD, -1}, |
||
1010 | {DVO_PORT_CRT, DVO_PORT_HDMIE, DVO_PORT_DPE}, |
||
4560 | Serge | 1011 | }; |
1012 | |||
1013 | /* Find the child device to use, abort if more than one found. */ |
||
1014 | for (i = 0; i < dev_priv->vbt.child_dev_num; i++) { |
||
1015 | it = dev_priv->vbt.child_dev + i; |
||
1016 | |||
6084 | serge | 1017 | for (j = 0; j < 3; j++) { |
4560 | Serge | 1018 | if (dvo_ports[port][j] == -1) |
1019 | break; |
||
1020 | |||
1021 | if (it->common.dvo_port == dvo_ports[port][j]) { |
||
1022 | if (child) { |
||
1023 | DRM_DEBUG_KMS("More than one child device for port %c in VBT.\n", |
||
1024 | port_name(port)); |
||
1025 | return; |
||
1026 | } |
||
1027 | child = it; |
||
1028 | } |
||
1029 | } |
||
1030 | } |
||
1031 | if (!child) |
||
1032 | return; |
||
1033 | |||
1034 | aux_channel = child->raw[25]; |
||
6084 | serge | 1035 | ddc_pin = child->common.ddc_pin; |
4560 | Serge | 1036 | |
1037 | is_dvi = child->common.device_type & DEVICE_TYPE_TMDS_DVI_SIGNALING; |
||
1038 | is_dp = child->common.device_type & DEVICE_TYPE_DISPLAYPORT_OUTPUT; |
||
1039 | is_crt = child->common.device_type & DEVICE_TYPE_ANALOG_OUTPUT; |
||
1040 | is_hdmi = is_dvi && (child->common.device_type & DEVICE_TYPE_NOT_HDMI_OUTPUT) == 0; |
||
1041 | is_edp = is_dp && (child->common.device_type & DEVICE_TYPE_INTERNAL_CONNECTOR); |
||
1042 | |||
1043 | info->supports_dvi = is_dvi; |
||
1044 | info->supports_hdmi = is_hdmi; |
||
1045 | info->supports_dp = is_dp; |
||
1046 | |||
1047 | DRM_DEBUG_KMS("Port %c VBT info: DP:%d HDMI:%d DVI:%d EDP:%d CRT:%d\n", |
||
1048 | port_name(port), is_dp, is_hdmi, is_dvi, is_edp, is_crt); |
||
1049 | |||
1050 | if (is_edp && is_dvi) |
||
1051 | DRM_DEBUG_KMS("Internal DP port %c is TMDS compatible\n", |
||
1052 | port_name(port)); |
||
1053 | if (is_crt && port != PORT_E) |
||
1054 | DRM_DEBUG_KMS("Port %c is analog\n", port_name(port)); |
||
1055 | if (is_crt && (is_dvi || is_dp)) |
||
1056 | DRM_DEBUG_KMS("Analog port %c is also DP or TMDS compatible\n", |
||
1057 | port_name(port)); |
||
1058 | if (is_dvi && (port == PORT_A || port == PORT_E)) |
||
5354 | serge | 1059 | DRM_DEBUG_KMS("Port %c is TMDS compatible\n", port_name(port)); |
4560 | Serge | 1060 | if (!is_dvi && !is_dp && !is_crt) |
1061 | DRM_DEBUG_KMS("Port %c is not DP/TMDS/CRT compatible\n", |
||
1062 | port_name(port)); |
||
1063 | if (is_edp && (port == PORT_B || port == PORT_C || port == PORT_E)) |
||
1064 | DRM_DEBUG_KMS("Port %c is internal DP\n", port_name(port)); |
||
1065 | |||
1066 | if (is_dvi) { |
||
6084 | serge | 1067 | if (port == PORT_E) { |
1068 | info->alternate_ddc_pin = ddc_pin; |
||
1069 | /* if DDIE share ddc pin with other port, then |
||
1070 | * dvi/hdmi couldn't exist on the shared port. |
||
1071 | * Otherwise they share the same ddc bin and system |
||
1072 | * couldn't communicate with them seperately. */ |
||
1073 | if (ddc_pin == DDC_PIN_B) { |
||
1074 | dev_priv->vbt.ddi_port_info[PORT_B].supports_dvi = 0; |
||
1075 | dev_priv->vbt.ddi_port_info[PORT_B].supports_hdmi = 0; |
||
1076 | } else if (ddc_pin == DDC_PIN_C) { |
||
1077 | dev_priv->vbt.ddi_port_info[PORT_C].supports_dvi = 0; |
||
1078 | dev_priv->vbt.ddi_port_info[PORT_C].supports_hdmi = 0; |
||
1079 | } else if (ddc_pin == DDC_PIN_D) { |
||
1080 | dev_priv->vbt.ddi_port_info[PORT_D].supports_dvi = 0; |
||
1081 | dev_priv->vbt.ddi_port_info[PORT_D].supports_hdmi = 0; |
||
1082 | } |
||
1083 | } else if (ddc_pin == DDC_PIN_B && port != PORT_B) |
||
4560 | Serge | 1084 | DRM_DEBUG_KMS("Unexpected DDC pin for port B\n"); |
6084 | serge | 1085 | else if (ddc_pin == DDC_PIN_C && port != PORT_C) |
4560 | Serge | 1086 | DRM_DEBUG_KMS("Unexpected DDC pin for port C\n"); |
6084 | serge | 1087 | else if (ddc_pin == DDC_PIN_D && port != PORT_D) |
4560 | Serge | 1088 | DRM_DEBUG_KMS("Unexpected DDC pin for port D\n"); |
1089 | } |
||
1090 | |||
1091 | if (is_dp) { |
||
6084 | serge | 1092 | if (port == PORT_E) { |
1093 | info->alternate_aux_channel = aux_channel; |
||
1094 | /* if DDIE share aux channel with other port, then |
||
1095 | * DP couldn't exist on the shared port. Otherwise |
||
1096 | * they share the same aux channel and system |
||
1097 | * couldn't communicate with them seperately. */ |
||
1098 | if (aux_channel == DP_AUX_A) |
||
1099 | dev_priv->vbt.ddi_port_info[PORT_A].supports_dp = 0; |
||
1100 | else if (aux_channel == DP_AUX_B) |
||
1101 | dev_priv->vbt.ddi_port_info[PORT_B].supports_dp = 0; |
||
1102 | else if (aux_channel == DP_AUX_C) |
||
1103 | dev_priv->vbt.ddi_port_info[PORT_C].supports_dp = 0; |
||
1104 | else if (aux_channel == DP_AUX_D) |
||
1105 | dev_priv->vbt.ddi_port_info[PORT_D].supports_dp = 0; |
||
1106 | } |
||
1107 | else if (aux_channel == DP_AUX_A && port != PORT_A) |
||
4560 | Serge | 1108 | DRM_DEBUG_KMS("Unexpected AUX channel for port A\n"); |
6084 | serge | 1109 | else if (aux_channel == DP_AUX_B && port != PORT_B) |
4560 | Serge | 1110 | DRM_DEBUG_KMS("Unexpected AUX channel for port B\n"); |
6084 | serge | 1111 | else if (aux_channel == DP_AUX_C && port != PORT_C) |
4560 | Serge | 1112 | DRM_DEBUG_KMS("Unexpected AUX channel for port C\n"); |
6084 | serge | 1113 | else if (aux_channel == DP_AUX_D && port != PORT_D) |
4560 | Serge | 1114 | DRM_DEBUG_KMS("Unexpected AUX channel for port D\n"); |
1115 | } |
||
1116 | |||
1117 | if (bdb->version >= 158) { |
||
1118 | /* The VBT HDMI level shift values match the table we have. */ |
||
1119 | hdmi_level_shift = child->raw[7] & 0xF; |
||
6084 | serge | 1120 | DRM_DEBUG_KMS("VBT HDMI level shift for port %c: %d\n", |
1121 | port_name(port), |
||
1122 | hdmi_level_shift); |
||
1123 | info->hdmi_level_shift = hdmi_level_shift; |
||
1124 | } |
||
1125 | |||
1126 | /* Parse the I_boost config for SKL and above */ |
||
1127 | if (bdb->version >= 196 && (child->common.flags_1 & IBOOST_ENABLE)) { |
||
1128 | info->dp_boost_level = translate_iboost(child->common.iboost_level & 0xF); |
||
1129 | DRM_DEBUG_KMS("VBT (e)DP boost level for port %c: %d\n", |
||
1130 | port_name(port), info->dp_boost_level); |
||
1131 | info->hdmi_boost_level = translate_iboost(child->common.iboost_level >> 4); |
||
1132 | DRM_DEBUG_KMS("VBT HDMI boost level for port %c: %d\n", |
||
1133 | port_name(port), info->hdmi_boost_level); |
||
1134 | } |
||
4560 | Serge | 1135 | } |
1136 | |||
1137 | static void parse_ddi_ports(struct drm_i915_private *dev_priv, |
||
6084 | serge | 1138 | const struct bdb_header *bdb) |
4560 | Serge | 1139 | { |
1140 | enum port port; |
||
1141 | |||
6937 | serge | 1142 | if (!HAS_DDI(dev_priv)) |
4560 | Serge | 1143 | return; |
1144 | |||
1145 | if (!dev_priv->vbt.child_dev_num) |
||
1146 | return; |
||
1147 | |||
1148 | if (bdb->version < 155) |
||
1149 | return; |
||
1150 | |||
1151 | for (port = PORT_A; port < I915_MAX_PORTS; port++) |
||
1152 | parse_ddi_port(dev_priv, port, bdb); |
||
1153 | } |
||
1154 | |||
1155 | static void |
||
2351 | Serge | 1156 | parse_device_mapping(struct drm_i915_private *dev_priv, |
6084 | serge | 1157 | const struct bdb_header *bdb) |
2351 | Serge | 1158 | { |
6084 | serge | 1159 | const struct bdb_general_definitions *p_defs; |
1160 | const union child_device_config *p_child; |
||
1161 | union child_device_config *child_dev_ptr; |
||
2351 | Serge | 1162 | int i, child_device_num, count; |
6084 | serge | 1163 | u8 expected_size; |
1164 | u16 block_size; |
||
2351 | Serge | 1165 | |
1166 | p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS); |
||
1167 | if (!p_defs) { |
||
1168 | DRM_DEBUG_KMS("No general definition block is found, no devices defined.\n"); |
||
1169 | return; |
||
1170 | } |
||
7144 | serge | 1171 | if (bdb->version < 106) { |
1172 | expected_size = 22; |
||
1173 | } else if (bdb->version < 109) { |
||
1174 | expected_size = 27; |
||
1175 | } else if (bdb->version < 195) { |
||
1176 | BUILD_BUG_ON(sizeof(struct old_child_dev_config) != 33); |
||
6084 | serge | 1177 | expected_size = sizeof(struct old_child_dev_config); |
1178 | } else if (bdb->version == 195) { |
||
1179 | expected_size = 37; |
||
1180 | } else if (bdb->version <= 197) { |
||
1181 | expected_size = 38; |
||
1182 | } else { |
||
1183 | expected_size = 38; |
||
1184 | BUILD_BUG_ON(sizeof(*p_child) < 38); |
||
1185 | DRM_DEBUG_DRIVER("Expected child device config size for VBT version %u not known; assuming %u\n", |
||
1186 | bdb->version, expected_size); |
||
1187 | } |
||
1188 | |||
7144 | serge | 1189 | /* Flag an error for unexpected size, but continue anyway. */ |
1190 | if (p_defs->child_dev_size != expected_size) |
||
1191 | DRM_ERROR("Unexpected child device config size %u (expected %u for VBT version %u)\n", |
||
1192 | p_defs->child_dev_size, expected_size, bdb->version); |
||
1193 | |||
6084 | serge | 1194 | /* The legacy sized child device config is the minimum we need. */ |
1195 | if (p_defs->child_dev_size < sizeof(struct old_child_dev_config)) { |
||
7144 | serge | 1196 | DRM_DEBUG_KMS("Child device config size %u is too small.\n", |
1197 | p_defs->child_dev_size); |
||
2351 | Serge | 1198 | return; |
1199 | } |
||
6084 | serge | 1200 | |
2351 | Serge | 1201 | /* get the block size of general definitions */ |
1202 | block_size = get_blocksize(p_defs); |
||
1203 | /* get the number of child device */ |
||
1204 | child_device_num = (block_size - sizeof(*p_defs)) / |
||
6084 | serge | 1205 | p_defs->child_dev_size; |
2351 | Serge | 1206 | count = 0; |
1207 | /* get the number of child device that is present */ |
||
1208 | for (i = 0; i < child_device_num; i++) { |
||
6084 | serge | 1209 | p_child = child_device_ptr(p_defs, i); |
4560 | Serge | 1210 | if (!p_child->common.device_type) { |
2351 | Serge | 1211 | /* skip the device block if device type is invalid */ |
1212 | continue; |
||
1213 | } |
||
1214 | count++; |
||
1215 | } |
||
1216 | if (!count) { |
||
1217 | DRM_DEBUG_KMS("no child dev is parsed from VBT\n"); |
||
1218 | return; |
||
1219 | } |
||
4104 | Serge | 1220 | dev_priv->vbt.child_dev = kcalloc(count, sizeof(*p_child), GFP_KERNEL); |
1221 | if (!dev_priv->vbt.child_dev) { |
||
2351 | Serge | 1222 | DRM_DEBUG_KMS("No memory space for child device\n"); |
1223 | return; |
||
1224 | } |
||
1225 | |||
4104 | Serge | 1226 | dev_priv->vbt.child_dev_num = count; |
2351 | Serge | 1227 | count = 0; |
1228 | for (i = 0; i < child_device_num; i++) { |
||
6084 | serge | 1229 | p_child = child_device_ptr(p_defs, i); |
4560 | Serge | 1230 | if (!p_child->common.device_type) { |
2351 | Serge | 1231 | /* skip the device block if device type is invalid */ |
1232 | continue; |
||
1233 | } |
||
5060 | serge | 1234 | |
1235 | if (p_child->common.dvo_port >= DVO_PORT_MIPIA |
||
1236 | && p_child->common.dvo_port <= DVO_PORT_MIPID |
||
1237 | &&p_child->common.device_type & DEVICE_TYPE_MIPI_OUTPUT) { |
||
1238 | DRM_DEBUG_KMS("Found MIPI as LFP\n"); |
||
1239 | dev_priv->vbt.has_mipi = 1; |
||
1240 | dev_priv->vbt.dsi.port = p_child->common.dvo_port; |
||
1241 | } |
||
1242 | |||
4104 | Serge | 1243 | child_dev_ptr = dev_priv->vbt.child_dev + count; |
2351 | Serge | 1244 | count++; |
6084 | serge | 1245 | |
1246 | /* |
||
1247 | * Copy as much as we know (sizeof) and is available |
||
1248 | * (child_dev_size) of the child device. Accessing the data must |
||
1249 | * depend on VBT version. |
||
1250 | */ |
||
1251 | memcpy(child_dev_ptr, p_child, |
||
1252 | min_t(size_t, p_defs->child_dev_size, sizeof(*p_child))); |
||
2351 | Serge | 1253 | } |
1254 | return; |
||
1255 | } |
||
1256 | |||
1257 | static void |
||
1258 | init_vbt_defaults(struct drm_i915_private *dev_priv) |
||
1259 | { |
||
4560 | Serge | 1260 | enum port port; |
2351 | Serge | 1261 | |
6084 | serge | 1262 | dev_priv->vbt.crt_ddc_pin = GMBUS_PIN_VGADDC; |
2351 | Serge | 1263 | |
5060 | serge | 1264 | /* Default to having backlight */ |
1265 | dev_priv->vbt.backlight.present = true; |
||
1266 | |||
2351 | Serge | 1267 | /* LFP panel data */ |
4104 | Serge | 1268 | dev_priv->vbt.lvds_dither = 1; |
1269 | dev_priv->vbt.lvds_vbt = 0; |
||
2351 | Serge | 1270 | |
1271 | /* SDVO panel data */ |
||
4104 | Serge | 1272 | dev_priv->vbt.sdvo_lvds_vbt_mode = NULL; |
2351 | Serge | 1273 | |
1274 | /* general features */ |
||
4104 | Serge | 1275 | dev_priv->vbt.int_tv_support = 1; |
1276 | dev_priv->vbt.int_crt_support = 1; |
||
2351 | Serge | 1277 | |
1278 | /* Default to using SSC */ |
||
4104 | Serge | 1279 | dev_priv->vbt.lvds_use_ssc = 1; |
4560 | Serge | 1280 | /* |
1281 | * Core/SandyBridge/IvyBridge use alternative (120MHz) reference |
||
1282 | * clock for LVDS. |
||
1283 | */ |
||
6937 | serge | 1284 | dev_priv->vbt.lvds_ssc_freq = intel_bios_ssc_frequency(dev_priv, |
1285 | !HAS_PCH_SPLIT(dev_priv)); |
||
4560 | Serge | 1286 | DRM_DEBUG_KMS("Set default to SSC at %d kHz\n", dev_priv->vbt.lvds_ssc_freq); |
1287 | |||
1288 | for (port = PORT_A; port < I915_MAX_PORTS; port++) { |
||
1289 | struct ddi_vbt_port_info *info = |
||
1290 | &dev_priv->vbt.ddi_port_info[port]; |
||
1291 | |||
5354 | serge | 1292 | info->hdmi_level_shift = HDMI_LEVEL_SHIFT_UNKNOWN; |
4560 | Serge | 1293 | |
1294 | info->supports_dvi = (port != PORT_A && port != PORT_E); |
||
1295 | info->supports_hdmi = info->supports_dvi; |
||
1296 | info->supports_dp = (port != PORT_E); |
||
1297 | } |
||
2351 | Serge | 1298 | } |
1299 | |||
6937 | serge | 1300 | static const struct bdb_header *get_bdb_header(const struct vbt_header *vbt) |
5097 | serge | 1301 | { |
6937 | serge | 1302 | const void *_vbt = vbt; |
1303 | |||
1304 | return _vbt + vbt->bdb_offset; |
||
5097 | serge | 1305 | } |
1306 | |||
6937 | serge | 1307 | /** |
1308 | * intel_bios_is_valid_vbt - does the given buffer contain a valid VBT |
||
1309 | * @buf: pointer to a buffer to validate |
||
1310 | * @size: size of the buffer |
||
1311 | * |
||
1312 | * Returns true on valid VBT. |
||
1313 | */ |
||
1314 | bool intel_bios_is_valid_vbt(const void *buf, size_t size) |
||
7144 | serge | 1315 | { |
6937 | serge | 1316 | const struct vbt_header *vbt = buf; |
6084 | serge | 1317 | const struct bdb_header *bdb; |
3120 | serge | 1318 | |
6937 | serge | 1319 | if (!vbt) |
1320 | return false; |
||
1321 | |||
1322 | if (sizeof(struct vbt_header) > size) { |
||
5060 | serge | 1323 | DRM_DEBUG_DRIVER("VBT header incomplete\n"); |
6937 | serge | 1324 | return false; |
5060 | serge | 1325 | } |
1326 | |||
1327 | if (memcmp(vbt->signature, "$VBT", 4)) { |
||
1328 | DRM_DEBUG_DRIVER("VBT invalid signature\n"); |
||
6937 | serge | 1329 | return false; |
5060 | serge | 1330 | } |
1331 | |||
6937 | serge | 1332 | if (vbt->bdb_offset + sizeof(struct bdb_header) > size) { |
5060 | serge | 1333 | DRM_DEBUG_DRIVER("BDB header incomplete\n"); |
6937 | serge | 1334 | return false; |
5060 | serge | 1335 | } |
1336 | |||
6937 | serge | 1337 | bdb = get_bdb_header(vbt); |
1338 | if (vbt->bdb_offset + bdb->bdb_size > size) { |
||
5060 | serge | 1339 | DRM_DEBUG_DRIVER("BDB incomplete\n"); |
6937 | serge | 1340 | return false; |
5060 | serge | 1341 | } |
1342 | |||
6937 | serge | 1343 | return vbt; |
5060 | serge | 1344 | } |
1345 | |||
6937 | serge | 1346 | static const struct vbt_header *find_vbt(void __iomem *bios, size_t size) |
6084 | serge | 1347 | { |
1348 | size_t i; |
||
1349 | |||
1350 | /* Scour memory looking for the VBT signature. */ |
||
1351 | for (i = 0; i + 4 < size; i++) { |
||
6937 | serge | 1352 | void *vbt; |
1353 | |||
1354 | if (ioread32(bios + i) != *((const u32 *) "$VBT")) |
||
1355 | continue; |
||
1356 | |||
7144 | serge | 1357 | /* |
6937 | serge | 1358 | * This is the one place where we explicitly discard the address |
1359 | * space (__iomem) of the BIOS/VBT. |
||
7144 | serge | 1360 | */ |
6937 | serge | 1361 | vbt = (void __force *) bios + i; |
1362 | if (intel_bios_is_valid_vbt(vbt, size - i)) |
||
1363 | return vbt; |
||
6084 | serge | 1364 | |
7144 | serge | 1365 | break; |
1366 | } |
||
6084 | serge | 1367 | |
6937 | serge | 1368 | return NULL; |
6084 | serge | 1369 | } |
1370 | |||
2351 | Serge | 1371 | /** |
6937 | serge | 1372 | * intel_bios_init - find VBT and initialize settings from the BIOS |
7144 | serge | 1373 | * @dev_priv: i915 device instance |
2351 | Serge | 1374 | * |
1375 | * Loads the Video BIOS and checks that the VBT exists. Sets scratch registers |
||
1376 | * to appropriate values. |
||
1377 | * |
||
1378 | * Returns 0 on success, nonzero on failure. |
||
1379 | */ |
||
3031 | serge | 1380 | int |
6937 | serge | 1381 | intel_bios_init(struct drm_i915_private *dev_priv) |
2351 | Serge | 1382 | { |
6937 | serge | 1383 | struct pci_dev *pdev = dev_priv->dev->pdev; |
1384 | const struct vbt_header *vbt = dev_priv->opregion.vbt; |
||
1385 | const struct bdb_header *bdb; |
||
2351 | Serge | 1386 | u8 __iomem *bios = NULL; |
1387 | |||
6937 | serge | 1388 | if (HAS_PCH_NOP(dev_priv)) |
3746 | Serge | 1389 | return -ENODEV; |
1390 | |||
2351 | Serge | 1391 | init_vbt_defaults(dev_priv); |
1392 | |||
6937 | serge | 1393 | if (!vbt) { |
6084 | serge | 1394 | size_t size; |
2351 | Serge | 1395 | |
2360 | Serge | 1396 | bios = pci_map_rom(pdev, &size); |
2351 | Serge | 1397 | if (!bios) |
1398 | return -1; |
||
1399 | |||
6937 | serge | 1400 | vbt = find_vbt(bios, size); |
1401 | if (!vbt) { |
||
2351 | Serge | 1402 | pci_unmap_rom(pdev, bios); |
1403 | return -1; |
||
1404 | } |
||
6937 | serge | 1405 | |
1406 | DRM_DEBUG_KMS("Found valid VBT in PCI ROM\n"); |
||
2351 | Serge | 1407 | } |
1408 | |||
6937 | serge | 1409 | bdb = get_bdb_header(vbt); |
1410 | |||
1411 | DRM_DEBUG_KMS("VBT signature \"%.*s\", BDB version %d\n", |
||
1412 | (int)sizeof(vbt->signature), vbt->signature, bdb->version); |
||
1413 | |||
2351 | Serge | 1414 | /* Grab useful general definitions */ |
1415 | parse_general_features(dev_priv, bdb); |
||
1416 | parse_general_definitions(dev_priv, bdb); |
||
1417 | parse_lfp_panel_data(dev_priv, bdb); |
||
4560 | Serge | 1418 | parse_lfp_backlight(dev_priv, bdb); |
2351 | Serge | 1419 | parse_sdvo_panel_data(dev_priv, bdb); |
1420 | parse_sdvo_device_mapping(dev_priv, bdb); |
||
1421 | parse_device_mapping(dev_priv, bdb); |
||
1422 | parse_driver_features(dev_priv, bdb); |
||
1423 | parse_edp(dev_priv, bdb); |
||
6084 | serge | 1424 | parse_psr(dev_priv, bdb); |
7144 | serge | 1425 | parse_mipi_config(dev_priv, bdb); |
1426 | parse_mipi_sequence(dev_priv, bdb); |
||
4560 | Serge | 1427 | parse_ddi_ports(dev_priv, bdb); |
2351 | Serge | 1428 | |
1429 | if (bios) |
||
1430 | pci_unmap_rom(pdev, bios); |
||
1431 | |||
1432 | return 0; |
||
1433 | }>>=>>>>>=>>>>>>>>>>>>>>>>><>><>><>><>><>> |