diff options
Diffstat (limited to 'drivers/gpu/drm/gma500/intel_bios.c')
-rw-r--r-- | drivers/gpu/drm/gma500/intel_bios.c | 274 |
1 files changed, 234 insertions, 40 deletions
diff --git a/drivers/gpu/drm/gma500/intel_bios.c b/drivers/gpu/drm/gma500/intel_bios.c index d4d0c5b8bf91..973d7f6d66b7 100644 --- a/drivers/gpu/drm/gma500/intel_bios.c +++ b/drivers/gpu/drm/gma500/intel_bios.c | |||
@@ -26,6 +26,8 @@ | |||
26 | #include "psb_intel_reg.h" | 26 | #include "psb_intel_reg.h" |
27 | #include "intel_bios.h" | 27 | #include "intel_bios.h" |
28 | 28 | ||
29 | #define SLAVE_ADDR1 0x70 | ||
30 | #define SLAVE_ADDR2 0x72 | ||
29 | 31 | ||
30 | static void *find_section(struct bdb_header *bdb, int section_id) | 32 | static void *find_section(struct bdb_header *bdb, int section_id) |
31 | { | 33 | { |
@@ -52,6 +54,16 @@ static void *find_section(struct bdb_header *bdb, int section_id) | |||
52 | return NULL; | 54 | return NULL; |
53 | } | 55 | } |
54 | 56 | ||
57 | static u16 | ||
58 | get_blocksize(void *p) | ||
59 | { | ||
60 | u16 *block_ptr, block_size; | ||
61 | |||
62 | block_ptr = (u16 *)((char *)p - 2); | ||
63 | block_size = *block_ptr; | ||
64 | return block_size; | ||
65 | } | ||
66 | |||
55 | static void fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode, | 67 | static void fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode, |
56 | struct lvds_dvo_timing *dvo_timing) | 68 | struct lvds_dvo_timing *dvo_timing) |
57 | { | 69 | { |
@@ -75,6 +87,16 @@ static void fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode, | |||
75 | panel_fixed_mode->clock = dvo_timing->clock * 10; | 87 | panel_fixed_mode->clock = dvo_timing->clock * 10; |
76 | panel_fixed_mode->type = DRM_MODE_TYPE_PREFERRED; | 88 | panel_fixed_mode->type = DRM_MODE_TYPE_PREFERRED; |
77 | 89 | ||
90 | if (dvo_timing->hsync_positive) | ||
91 | panel_fixed_mode->flags |= DRM_MODE_FLAG_PHSYNC; | ||
92 | else | ||
93 | panel_fixed_mode->flags |= DRM_MODE_FLAG_NHSYNC; | ||
94 | |||
95 | if (dvo_timing->vsync_positive) | ||
96 | panel_fixed_mode->flags |= DRM_MODE_FLAG_PVSYNC; | ||
97 | else | ||
98 | panel_fixed_mode->flags |= DRM_MODE_FLAG_NVSYNC; | ||
99 | |||
78 | /* Some VBTs have bogus h/vtotal values */ | 100 | /* Some VBTs have bogus h/vtotal values */ |
79 | if (panel_fixed_mode->hsync_end > panel_fixed_mode->htotal) | 101 | if (panel_fixed_mode->hsync_end > panel_fixed_mode->htotal) |
80 | panel_fixed_mode->htotal = panel_fixed_mode->hsync_end + 1; | 102 | panel_fixed_mode->htotal = panel_fixed_mode->hsync_end + 1; |
@@ -217,6 +239,180 @@ static void parse_general_features(struct drm_psb_private *dev_priv, | |||
217 | } | 239 | } |
218 | } | 240 | } |
219 | 241 | ||
242 | static void | ||
243 | parse_sdvo_device_mapping(struct drm_psb_private *dev_priv, | ||
244 | struct bdb_header *bdb) | ||
245 | { | ||
246 | struct sdvo_device_mapping *p_mapping; | ||
247 | struct bdb_general_definitions *p_defs; | ||
248 | struct child_device_config *p_child; | ||
249 | int i, child_device_num, count; | ||
250 | u16 block_size; | ||
251 | |||
252 | p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS); | ||
253 | if (!p_defs) { | ||
254 | DRM_DEBUG_KMS("No general definition block is found, unable to construct sdvo mapping.\n"); | ||
255 | return; | ||
256 | } | ||
257 | /* judge whether the size of child device meets the requirements. | ||
258 | * If the child device size obtained from general definition block | ||
259 | * is different with sizeof(struct child_device_config), skip the | ||
260 | * parsing of sdvo device info | ||
261 | */ | ||
262 | if (p_defs->child_dev_size != sizeof(*p_child)) { | ||
263 | /* different child dev size . Ignore it */ | ||
264 | DRM_DEBUG_KMS("different child size is found. Invalid.\n"); | ||
265 | return; | ||
266 | } | ||
267 | /* get the block size of general definitions */ | ||
268 | block_size = get_blocksize(p_defs); | ||
269 | /* get the number of child device */ | ||
270 | child_device_num = (block_size - sizeof(*p_defs)) / | ||
271 | sizeof(*p_child); | ||
272 | count = 0; | ||
273 | for (i = 0; i < child_device_num; i++) { | ||
274 | p_child = &(p_defs->devices[i]); | ||
275 | if (!p_child->device_type) { | ||
276 | /* skip the device block if device type is invalid */ | ||
277 | continue; | ||
278 | } | ||
279 | if (p_child->slave_addr != SLAVE_ADDR1 && | ||
280 | p_child->slave_addr != SLAVE_ADDR2) { | ||
281 | /* | ||
282 | * If the slave address is neither 0x70 nor 0x72, | ||
283 | * it is not a SDVO device. Skip it. | ||
284 | */ | ||
285 | continue; | ||
286 | } | ||
287 | if (p_child->dvo_port != DEVICE_PORT_DVOB && | ||
288 | p_child->dvo_port != DEVICE_PORT_DVOC) { | ||
289 | /* skip the incorrect SDVO port */ | ||
290 | DRM_DEBUG_KMS("Incorrect SDVO port. Skip it\n"); | ||
291 | continue; | ||
292 | } | ||
293 | DRM_DEBUG_KMS("the SDVO device with slave addr %2x is found on" | ||
294 | " %s port\n", | ||
295 | p_child->slave_addr, | ||
296 | (p_child->dvo_port == DEVICE_PORT_DVOB) ? | ||
297 | "SDVOB" : "SDVOC"); | ||
298 | p_mapping = &(dev_priv->sdvo_mappings[p_child->dvo_port - 1]); | ||
299 | if (!p_mapping->initialized) { | ||
300 | p_mapping->dvo_port = p_child->dvo_port; | ||
301 | p_mapping->slave_addr = p_child->slave_addr; | ||
302 | p_mapping->dvo_wiring = p_child->dvo_wiring; | ||
303 | p_mapping->ddc_pin = p_child->ddc_pin; | ||
304 | p_mapping->i2c_pin = p_child->i2c_pin; | ||
305 | p_mapping->initialized = 1; | ||
306 | DRM_DEBUG_KMS("SDVO device: dvo=%x, addr=%x, wiring=%d, ddc_pin=%d, i2c_pin=%d\n", | ||
307 | p_mapping->dvo_port, | ||
308 | p_mapping->slave_addr, | ||
309 | p_mapping->dvo_wiring, | ||
310 | p_mapping->ddc_pin, | ||
311 | p_mapping->i2c_pin); | ||
312 | } else { | ||
313 | DRM_DEBUG_KMS("Maybe one SDVO port is shared by " | ||
314 | "two SDVO device.\n"); | ||
315 | } | ||
316 | if (p_child->slave2_addr) { | ||
317 | /* Maybe this is a SDVO device with multiple inputs */ | ||
318 | /* And the mapping info is not added */ | ||
319 | DRM_DEBUG_KMS("there exists the slave2_addr. Maybe this" | ||
320 | " is a SDVO device with multiple inputs.\n"); | ||
321 | } | ||
322 | count++; | ||
323 | } | ||
324 | |||
325 | if (!count) { | ||
326 | /* No SDVO device info is found */ | ||
327 | DRM_DEBUG_KMS("No SDVO device info is found in VBT\n"); | ||
328 | } | ||
329 | return; | ||
330 | } | ||
331 | |||
332 | |||
333 | static void | ||
334 | parse_driver_features(struct drm_psb_private *dev_priv, | ||
335 | struct bdb_header *bdb) | ||
336 | { | ||
337 | struct bdb_driver_features *driver; | ||
338 | |||
339 | driver = find_section(bdb, BDB_DRIVER_FEATURES); | ||
340 | if (!driver) | ||
341 | return; | ||
342 | |||
343 | /* This bit means to use 96Mhz for DPLL_A or not */ | ||
344 | if (driver->primary_lfp_id) | ||
345 | dev_priv->dplla_96mhz = true; | ||
346 | else | ||
347 | dev_priv->dplla_96mhz = false; | ||
348 | } | ||
349 | |||
350 | static void | ||
351 | parse_device_mapping(struct drm_psb_private *dev_priv, | ||
352 | struct bdb_header *bdb) | ||
353 | { | ||
354 | struct bdb_general_definitions *p_defs; | ||
355 | struct child_device_config *p_child, *child_dev_ptr; | ||
356 | int i, child_device_num, count; | ||
357 | u16 block_size; | ||
358 | |||
359 | p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS); | ||
360 | if (!p_defs) { | ||
361 | DRM_DEBUG_KMS("No general definition block is found, no devices defined.\n"); | ||
362 | return; | ||
363 | } | ||
364 | /* judge whether the size of child device meets the requirements. | ||
365 | * If the child device size obtained from general definition block | ||
366 | * is different with sizeof(struct child_device_config), skip the | ||
367 | * parsing of sdvo device info | ||
368 | */ | ||
369 | if (p_defs->child_dev_size != sizeof(*p_child)) { | ||
370 | /* different child dev size . Ignore it */ | ||
371 | DRM_DEBUG_KMS("different child size is found. Invalid.\n"); | ||
372 | return; | ||
373 | } | ||
374 | /* get the block size of general definitions */ | ||
375 | block_size = get_blocksize(p_defs); | ||
376 | /* get the number of child device */ | ||
377 | child_device_num = (block_size - sizeof(*p_defs)) / | ||
378 | sizeof(*p_child); | ||
379 | count = 0; | ||
380 | /* get the number of child devices that are present */ | ||
381 | for (i = 0; i < child_device_num; i++) { | ||
382 | p_child = &(p_defs->devices[i]); | ||
383 | if (!p_child->device_type) { | ||
384 | /* skip the device block if device type is invalid */ | ||
385 | continue; | ||
386 | } | ||
387 | count++; | ||
388 | } | ||
389 | if (!count) { | ||
390 | DRM_DEBUG_KMS("no child dev is parsed from VBT\n"); | ||
391 | return; | ||
392 | } | ||
393 | dev_priv->child_dev = kcalloc(count, sizeof(*p_child), GFP_KERNEL); | ||
394 | if (!dev_priv->child_dev) { | ||
395 | DRM_DEBUG_KMS("No memory space for child devices\n"); | ||
396 | return; | ||
397 | } | ||
398 | |||
399 | dev_priv->child_dev_num = count; | ||
400 | count = 0; | ||
401 | for (i = 0; i < child_device_num; i++) { | ||
402 | p_child = &(p_defs->devices[i]); | ||
403 | if (!p_child->device_type) { | ||
404 | /* skip the device block if device type is invalid */ | ||
405 | continue; | ||
406 | } | ||
407 | child_dev_ptr = dev_priv->child_dev + count; | ||
408 | count++; | ||
409 | memcpy((void *)child_dev_ptr, (void *)p_child, | ||
410 | sizeof(*p_child)); | ||
411 | } | ||
412 | return; | ||
413 | } | ||
414 | |||
415 | |||
220 | /** | 416 | /** |
221 | * psb_intel_init_bios - initialize VBIOS settings & find VBT | 417 | * psb_intel_init_bios - initialize VBIOS settings & find VBT |
222 | * @dev: DRM device | 418 | * @dev: DRM device |
@@ -236,38 +432,54 @@ bool psb_intel_init_bios(struct drm_device *dev) | |||
236 | struct drm_psb_private *dev_priv = dev->dev_private; | 432 | struct drm_psb_private *dev_priv = dev->dev_private; |
237 | struct pci_dev *pdev = dev->pdev; | 433 | struct pci_dev *pdev = dev->pdev; |
238 | struct vbt_header *vbt = NULL; | 434 | struct vbt_header *vbt = NULL; |
239 | struct bdb_header *bdb; | 435 | struct bdb_header *bdb = NULL; |
240 | u8 __iomem *bios; | 436 | u8 __iomem *bios = NULL; |
241 | size_t size; | 437 | size_t size; |
242 | int i; | 438 | int i; |
243 | 439 | ||
244 | bios = pci_map_rom(pdev, &size); | 440 | /* XXX Should this validation be moved to intel_opregion.c? */ |
245 | if (!bios) | 441 | if (dev_priv->opregion.vbt) { |
246 | return -1; | 442 | struct vbt_header *vbt = dev_priv->opregion.vbt; |
443 | if (memcmp(vbt->signature, "$VBT", 4) == 0) { | ||
444 | DRM_DEBUG_KMS("Using VBT from OpRegion: %20s\n", | ||
445 | vbt->signature); | ||
446 | bdb = (struct bdb_header *)((char *)vbt + vbt->bdb_offset); | ||
447 | } else | ||
448 | dev_priv->opregion.vbt = NULL; | ||
449 | } | ||
247 | 450 | ||
248 | /* Scour memory looking for the VBT signature */ | 451 | if (bdb == NULL) { |
249 | for (i = 0; i + 4 < size; i++) { | 452 | bios = pci_map_rom(pdev, &size); |
250 | if (!memcmp(bios + i, "$VBT", 4)) { | 453 | if (!bios) |
251 | vbt = (struct vbt_header *)(bios + i); | 454 | return -1; |
252 | break; | 455 | |
456 | /* Scour memory looking for the VBT signature */ | ||
457 | for (i = 0; i + 4 < size; i++) { | ||
458 | if (!memcmp(bios + i, "$VBT", 4)) { | ||
459 | vbt = (struct vbt_header *)(bios + i); | ||
460 | break; | ||
461 | } | ||
253 | } | 462 | } |
254 | } | ||
255 | 463 | ||
256 | if (!vbt) { | 464 | if (!vbt) { |
257 | dev_err(dev->dev, "VBT signature missing\n"); | 465 | dev_err(dev->dev, "VBT signature missing\n"); |
258 | pci_unmap_rom(pdev, bios); | 466 | pci_unmap_rom(pdev, bios); |
259 | return -1; | 467 | return -1; |
468 | } | ||
469 | bdb = (struct bdb_header *)(bios + i + vbt->bdb_offset); | ||
260 | } | 470 | } |
261 | 471 | ||
262 | bdb = (struct bdb_header *)(bios + i + vbt->bdb_offset); | 472 | /* Grab useful general dxefinitions */ |
263 | |||
264 | /* Grab useful general definitions */ | ||
265 | parse_general_features(dev_priv, bdb); | 473 | parse_general_features(dev_priv, bdb); |
474 | parse_driver_features(dev_priv, bdb); | ||
266 | parse_lfp_panel_data(dev_priv, bdb); | 475 | parse_lfp_panel_data(dev_priv, bdb); |
267 | parse_sdvo_panel_data(dev_priv, bdb); | 476 | parse_sdvo_panel_data(dev_priv, bdb); |
477 | parse_sdvo_device_mapping(dev_priv, bdb); | ||
478 | parse_device_mapping(dev_priv, bdb); | ||
268 | parse_backlight_data(dev_priv, bdb); | 479 | parse_backlight_data(dev_priv, bdb); |
269 | 480 | ||
270 | pci_unmap_rom(pdev, bios); | 481 | if (bios) |
482 | pci_unmap_rom(pdev, bios); | ||
271 | 483 | ||
272 | return 0; | 484 | return 0; |
273 | } | 485 | } |
@@ -278,26 +490,8 @@ bool psb_intel_init_bios(struct drm_device *dev) | |||
278 | void psb_intel_destroy_bios(struct drm_device *dev) | 490 | void psb_intel_destroy_bios(struct drm_device *dev) |
279 | { | 491 | { |
280 | struct drm_psb_private *dev_priv = dev->dev_private; | 492 | struct drm_psb_private *dev_priv = dev->dev_private; |
281 | struct drm_display_mode *sdvo_lvds_vbt_mode = | ||
282 | dev_priv->sdvo_lvds_vbt_mode; | ||
283 | struct drm_display_mode *lfp_lvds_vbt_mode = | ||
284 | dev_priv->lfp_lvds_vbt_mode; | ||
285 | struct bdb_lvds_backlight *lvds_bl = | ||
286 | dev_priv->lvds_bl; | ||
287 | |||
288 | /*free sdvo panel mode*/ | ||
289 | if (sdvo_lvds_vbt_mode) { | ||
290 | dev_priv->sdvo_lvds_vbt_mode = NULL; | ||
291 | kfree(sdvo_lvds_vbt_mode); | ||
292 | } | ||
293 | 493 | ||
294 | if (lfp_lvds_vbt_mode) { | 494 | kfree(dev_priv->sdvo_lvds_vbt_mode); |
295 | dev_priv->lfp_lvds_vbt_mode = NULL; | 495 | kfree(dev_priv->lfp_lvds_vbt_mode); |
296 | kfree(lfp_lvds_vbt_mode); | 496 | kfree(dev_priv->lvds_bl); |
297 | } | ||
298 | |||
299 | if (lvds_bl) { | ||
300 | dev_priv->lvds_bl = NULL; | ||
301 | kfree(lvds_bl); | ||
302 | } | ||
303 | } | 497 | } |