diff options
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_display.c')
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_display.c | 427 |
1 files changed, 373 insertions, 54 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index c85df4afcb7a..bb1c122cad21 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c | |||
@@ -68,6 +68,36 @@ static void avivo_crtc_load_lut(struct drm_crtc *crtc) | |||
68 | WREG32(AVIVO_D1GRPH_LUT_SEL + radeon_crtc->crtc_offset, radeon_crtc->crtc_id); | 68 | WREG32(AVIVO_D1GRPH_LUT_SEL + radeon_crtc->crtc_offset, radeon_crtc->crtc_id); |
69 | } | 69 | } |
70 | 70 | ||
71 | static void evergreen_crtc_load_lut(struct drm_crtc *crtc) | ||
72 | { | ||
73 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); | ||
74 | struct drm_device *dev = crtc->dev; | ||
75 | struct radeon_device *rdev = dev->dev_private; | ||
76 | int i; | ||
77 | |||
78 | DRM_DEBUG("%d\n", radeon_crtc->crtc_id); | ||
79 | WREG32(EVERGREEN_DC_LUT_CONTROL + radeon_crtc->crtc_offset, 0); | ||
80 | |||
81 | WREG32(EVERGREEN_DC_LUT_BLACK_OFFSET_BLUE + radeon_crtc->crtc_offset, 0); | ||
82 | WREG32(EVERGREEN_DC_LUT_BLACK_OFFSET_GREEN + radeon_crtc->crtc_offset, 0); | ||
83 | WREG32(EVERGREEN_DC_LUT_BLACK_OFFSET_RED + radeon_crtc->crtc_offset, 0); | ||
84 | |||
85 | WREG32(EVERGREEN_DC_LUT_WHITE_OFFSET_BLUE + radeon_crtc->crtc_offset, 0xffff); | ||
86 | WREG32(EVERGREEN_DC_LUT_WHITE_OFFSET_GREEN + radeon_crtc->crtc_offset, 0xffff); | ||
87 | WREG32(EVERGREEN_DC_LUT_WHITE_OFFSET_RED + radeon_crtc->crtc_offset, 0xffff); | ||
88 | |||
89 | WREG32(EVERGREEN_DC_LUT_RW_MODE + radeon_crtc->crtc_offset, 0); | ||
90 | WREG32(EVERGREEN_DC_LUT_WRITE_EN_MASK + radeon_crtc->crtc_offset, 0x00000007); | ||
91 | |||
92 | WREG32(EVERGREEN_DC_LUT_RW_INDEX + radeon_crtc->crtc_offset, 0); | ||
93 | for (i = 0; i < 256; i++) { | ||
94 | WREG32(EVERGREEN_DC_LUT_30_COLOR + radeon_crtc->crtc_offset, | ||
95 | (radeon_crtc->lut_r[i] << 20) | | ||
96 | (radeon_crtc->lut_g[i] << 10) | | ||
97 | (radeon_crtc->lut_b[i] << 0)); | ||
98 | } | ||
99 | } | ||
100 | |||
71 | static void legacy_crtc_load_lut(struct drm_crtc *crtc) | 101 | static void legacy_crtc_load_lut(struct drm_crtc *crtc) |
72 | { | 102 | { |
73 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); | 103 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
@@ -100,7 +130,9 @@ void radeon_crtc_load_lut(struct drm_crtc *crtc) | |||
100 | if (!crtc->enabled) | 130 | if (!crtc->enabled) |
101 | return; | 131 | return; |
102 | 132 | ||
103 | if (ASIC_IS_AVIVO(rdev)) | 133 | if (ASIC_IS_DCE4(rdev)) |
134 | evergreen_crtc_load_lut(crtc); | ||
135 | else if (ASIC_IS_AVIVO(rdev)) | ||
104 | avivo_crtc_load_lut(crtc); | 136 | avivo_crtc_load_lut(crtc); |
105 | else | 137 | else |
106 | legacy_crtc_load_lut(crtc); | 138 | legacy_crtc_load_lut(crtc); |
@@ -234,7 +266,7 @@ static const char *encoder_names[34] = { | |||
234 | "INTERNAL_UNIPHY2", | 266 | "INTERNAL_UNIPHY2", |
235 | }; | 267 | }; |
236 | 268 | ||
237 | static const char *connector_names[13] = { | 269 | static const char *connector_names[15] = { |
238 | "Unknown", | 270 | "Unknown", |
239 | "VGA", | 271 | "VGA", |
240 | "DVI-I", | 272 | "DVI-I", |
@@ -248,6 +280,18 @@ static const char *connector_names[13] = { | |||
248 | "DisplayPort", | 280 | "DisplayPort", |
249 | "HDMI-A", | 281 | "HDMI-A", |
250 | "HDMI-B", | 282 | "HDMI-B", |
283 | "TV", | ||
284 | "eDP", | ||
285 | }; | ||
286 | |||
287 | static const char *hpd_names[7] = { | ||
288 | "NONE", | ||
289 | "HPD1", | ||
290 | "HPD2", | ||
291 | "HPD3", | ||
292 | "HPD4", | ||
293 | "HPD5", | ||
294 | "HPD6", | ||
251 | }; | 295 | }; |
252 | 296 | ||
253 | static void radeon_print_display_setup(struct drm_device *dev) | 297 | static void radeon_print_display_setup(struct drm_device *dev) |
@@ -264,16 +308,27 @@ static void radeon_print_display_setup(struct drm_device *dev) | |||
264 | radeon_connector = to_radeon_connector(connector); | 308 | radeon_connector = to_radeon_connector(connector); |
265 | DRM_INFO("Connector %d:\n", i); | 309 | DRM_INFO("Connector %d:\n", i); |
266 | DRM_INFO(" %s\n", connector_names[connector->connector_type]); | 310 | DRM_INFO(" %s\n", connector_names[connector->connector_type]); |
267 | if (radeon_connector->ddc_bus) | 311 | if (radeon_connector->hpd.hpd != RADEON_HPD_NONE) |
312 | DRM_INFO(" %s\n", hpd_names[radeon_connector->hpd.hpd]); | ||
313 | if (radeon_connector->ddc_bus) { | ||
268 | DRM_INFO(" DDC: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", | 314 | DRM_INFO(" DDC: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", |
269 | radeon_connector->ddc_bus->rec.mask_clk_reg, | 315 | radeon_connector->ddc_bus->rec.mask_clk_reg, |
270 | radeon_connector->ddc_bus->rec.mask_data_reg, | 316 | radeon_connector->ddc_bus->rec.mask_data_reg, |
271 | radeon_connector->ddc_bus->rec.a_clk_reg, | 317 | radeon_connector->ddc_bus->rec.a_clk_reg, |
272 | radeon_connector->ddc_bus->rec.a_data_reg, | 318 | radeon_connector->ddc_bus->rec.a_data_reg, |
273 | radeon_connector->ddc_bus->rec.put_clk_reg, | 319 | radeon_connector->ddc_bus->rec.en_clk_reg, |
274 | radeon_connector->ddc_bus->rec.put_data_reg, | 320 | radeon_connector->ddc_bus->rec.en_data_reg, |
275 | radeon_connector->ddc_bus->rec.get_clk_reg, | 321 | radeon_connector->ddc_bus->rec.y_clk_reg, |
276 | radeon_connector->ddc_bus->rec.get_data_reg); | 322 | radeon_connector->ddc_bus->rec.y_data_reg); |
323 | } else { | ||
324 | if (connector->connector_type == DRM_MODE_CONNECTOR_VGA || | ||
325 | connector->connector_type == DRM_MODE_CONNECTOR_DVII || | ||
326 | connector->connector_type == DRM_MODE_CONNECTOR_DVID || | ||
327 | connector->connector_type == DRM_MODE_CONNECTOR_DVIA || | ||
328 | connector->connector_type == DRM_MODE_CONNECTOR_HDMIA || | ||
329 | connector->connector_type == DRM_MODE_CONNECTOR_HDMIB) | ||
330 | DRM_INFO(" DDC: no ddc bus - possible BIOS bug - please report to xorg-driver-ati@lists.x.org\n"); | ||
331 | } | ||
277 | DRM_INFO(" Encoders:\n"); | 332 | DRM_INFO(" Encoders:\n"); |
278 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { | 333 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
279 | radeon_encoder = to_radeon_encoder(encoder); | 334 | radeon_encoder = to_radeon_encoder(encoder); |
@@ -313,17 +368,20 @@ static bool radeon_setup_enc_conn(struct drm_device *dev) | |||
313 | 368 | ||
314 | if (rdev->bios) { | 369 | if (rdev->bios) { |
315 | if (rdev->is_atom_bios) { | 370 | if (rdev->is_atom_bios) { |
316 | if (rdev->family >= CHIP_R600) | 371 | ret = radeon_get_atom_connector_info_from_supported_devices_table(dev); |
372 | if (ret == false) | ||
317 | ret = radeon_get_atom_connector_info_from_object_table(dev); | 373 | ret = radeon_get_atom_connector_info_from_object_table(dev); |
318 | else | 374 | } else { |
319 | ret = radeon_get_atom_connector_info_from_supported_devices_table(dev); | ||
320 | } else | ||
321 | ret = radeon_get_legacy_connector_info_from_bios(dev); | 375 | ret = radeon_get_legacy_connector_info_from_bios(dev); |
376 | if (ret == false) | ||
377 | ret = radeon_get_legacy_connector_info_from_table(dev); | ||
378 | } | ||
322 | } else { | 379 | } else { |
323 | if (!ASIC_IS_AVIVO(rdev)) | 380 | if (!ASIC_IS_AVIVO(rdev)) |
324 | ret = radeon_get_legacy_connector_info_from_table(dev); | 381 | ret = radeon_get_legacy_connector_info_from_table(dev); |
325 | } | 382 | } |
326 | if (ret) { | 383 | if (ret) { |
384 | radeon_setup_encoder_clones(dev); | ||
327 | radeon_print_display_setup(dev); | 385 | radeon_print_display_setup(dev); |
328 | list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head) | 386 | list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head) |
329 | radeon_ddc_dump(drm_connector); | 387 | radeon_ddc_dump(drm_connector); |
@@ -334,16 +392,25 @@ static bool radeon_setup_enc_conn(struct drm_device *dev) | |||
334 | 392 | ||
335 | int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) | 393 | int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) |
336 | { | 394 | { |
395 | struct drm_device *dev = radeon_connector->base.dev; | ||
396 | struct radeon_device *rdev = dev->dev_private; | ||
337 | int ret = 0; | 397 | int ret = 0; |
338 | 398 | ||
399 | if ((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) || | ||
400 | (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP)) { | ||
401 | struct radeon_connector_atom_dig *dig = radeon_connector->con_priv; | ||
402 | if ((dig->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT || | ||
403 | dig->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) && dig->dp_i2c_bus) | ||
404 | radeon_connector->edid = drm_get_edid(&radeon_connector->base, &dig->dp_i2c_bus->adapter); | ||
405 | } | ||
339 | if (!radeon_connector->ddc_bus) | 406 | if (!radeon_connector->ddc_bus) |
340 | return -1; | 407 | return -1; |
341 | if (!radeon_connector->edid) { | 408 | if (!radeon_connector->edid) { |
342 | radeon_i2c_do_lock(radeon_connector, 1); | ||
343 | radeon_connector->edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter); | 409 | radeon_connector->edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter); |
344 | radeon_i2c_do_lock(radeon_connector, 0); | ||
345 | } | 410 | } |
346 | 411 | /* some servers provide a hardcoded edid in rom for KVMs */ | |
412 | if (!radeon_connector->edid) | ||
413 | radeon_connector->edid = radeon_combios_get_hardcoded_edid(rdev); | ||
347 | if (radeon_connector->edid) { | 414 | if (radeon_connector->edid) { |
348 | drm_mode_connector_update_edid_property(&radeon_connector->base, radeon_connector->edid); | 415 | drm_mode_connector_update_edid_property(&radeon_connector->base, radeon_connector->edid); |
349 | ret = drm_add_edid_modes(&radeon_connector->base, radeon_connector->edid); | 416 | ret = drm_add_edid_modes(&radeon_connector->base, radeon_connector->edid); |
@@ -361,9 +428,7 @@ static int radeon_ddc_dump(struct drm_connector *connector) | |||
361 | 428 | ||
362 | if (!radeon_connector->ddc_bus) | 429 | if (!radeon_connector->ddc_bus) |
363 | return -1; | 430 | return -1; |
364 | radeon_i2c_do_lock(radeon_connector, 1); | ||
365 | edid = drm_get_edid(connector, &radeon_connector->ddc_bus->adapter); | 431 | edid = drm_get_edid(connector, &radeon_connector->ddc_bus->adapter); |
366 | radeon_i2c_do_lock(radeon_connector, 0); | ||
367 | if (edid) { | 432 | if (edid) { |
368 | kfree(edid); | 433 | kfree(edid); |
369 | } | 434 | } |
@@ -380,17 +445,18 @@ static inline uint32_t radeon_div(uint64_t n, uint32_t d) | |||
380 | return n; | 445 | return n; |
381 | } | 446 | } |
382 | 447 | ||
383 | void radeon_compute_pll(struct radeon_pll *pll, | 448 | static void radeon_compute_pll_legacy(struct radeon_pll *pll, |
384 | uint64_t freq, | 449 | uint64_t freq, |
385 | uint32_t *dot_clock_p, | 450 | uint32_t *dot_clock_p, |
386 | uint32_t *fb_div_p, | 451 | uint32_t *fb_div_p, |
387 | uint32_t *frac_fb_div_p, | 452 | uint32_t *frac_fb_div_p, |
388 | uint32_t *ref_div_p, | 453 | uint32_t *ref_div_p, |
389 | uint32_t *post_div_p, | 454 | uint32_t *post_div_p) |
390 | int flags) | ||
391 | { | 455 | { |
392 | uint32_t min_ref_div = pll->min_ref_div; | 456 | uint32_t min_ref_div = pll->min_ref_div; |
393 | uint32_t max_ref_div = pll->max_ref_div; | 457 | uint32_t max_ref_div = pll->max_ref_div; |
458 | uint32_t min_post_div = pll->min_post_div; | ||
459 | uint32_t max_post_div = pll->max_post_div; | ||
394 | uint32_t min_fractional_feed_div = 0; | 460 | uint32_t min_fractional_feed_div = 0; |
395 | uint32_t max_fractional_feed_div = 0; | 461 | uint32_t max_fractional_feed_div = 0; |
396 | uint32_t best_vco = pll->best_vco; | 462 | uint32_t best_vco = pll->best_vco; |
@@ -402,11 +468,20 @@ void radeon_compute_pll(struct radeon_pll *pll, | |||
402 | uint32_t best_error = 0xffffffff; | 468 | uint32_t best_error = 0xffffffff; |
403 | uint32_t best_vco_diff = 1; | 469 | uint32_t best_vco_diff = 1; |
404 | uint32_t post_div; | 470 | uint32_t post_div; |
471 | u32 pll_out_min, pll_out_max; | ||
405 | 472 | ||
406 | DRM_DEBUG("PLL freq %llu %u %u\n", freq, pll->min_ref_div, pll->max_ref_div); | 473 | DRM_DEBUG("PLL freq %llu %u %u\n", freq, pll->min_ref_div, pll->max_ref_div); |
407 | freq = freq * 1000; | 474 | freq = freq * 1000; |
408 | 475 | ||
409 | if (flags & RADEON_PLL_USE_REF_DIV) | 476 | if (pll->flags & RADEON_PLL_IS_LCD) { |
477 | pll_out_min = pll->lcd_pll_out_min; | ||
478 | pll_out_max = pll->lcd_pll_out_max; | ||
479 | } else { | ||
480 | pll_out_min = pll->pll_out_min; | ||
481 | pll_out_max = pll->pll_out_max; | ||
482 | } | ||
483 | |||
484 | if (pll->flags & RADEON_PLL_USE_REF_DIV) | ||
410 | min_ref_div = max_ref_div = pll->reference_div; | 485 | min_ref_div = max_ref_div = pll->reference_div; |
411 | else { | 486 | else { |
412 | while (min_ref_div < max_ref_div-1) { | 487 | while (min_ref_div < max_ref_div-1) { |
@@ -421,19 +496,22 @@ void radeon_compute_pll(struct radeon_pll *pll, | |||
421 | } | 496 | } |
422 | } | 497 | } |
423 | 498 | ||
424 | if (flags & RADEON_PLL_USE_FRAC_FB_DIV) { | 499 | if (pll->flags & RADEON_PLL_USE_POST_DIV) |
500 | min_post_div = max_post_div = pll->post_div; | ||
501 | |||
502 | if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) { | ||
425 | min_fractional_feed_div = pll->min_frac_feedback_div; | 503 | min_fractional_feed_div = pll->min_frac_feedback_div; |
426 | max_fractional_feed_div = pll->max_frac_feedback_div; | 504 | max_fractional_feed_div = pll->max_frac_feedback_div; |
427 | } | 505 | } |
428 | 506 | ||
429 | for (post_div = pll->min_post_div; post_div <= pll->max_post_div; ++post_div) { | 507 | for (post_div = min_post_div; post_div <= max_post_div; ++post_div) { |
430 | uint32_t ref_div; | 508 | uint32_t ref_div; |
431 | 509 | ||
432 | if ((flags & RADEON_PLL_NO_ODD_POST_DIV) && (post_div & 1)) | 510 | if ((pll->flags & RADEON_PLL_NO_ODD_POST_DIV) && (post_div & 1)) |
433 | continue; | 511 | continue; |
434 | 512 | ||
435 | /* legacy radeons only have a few post_divs */ | 513 | /* legacy radeons only have a few post_divs */ |
436 | if (flags & RADEON_PLL_LEGACY) { | 514 | if (pll->flags & RADEON_PLL_LEGACY) { |
437 | if ((post_div == 5) || | 515 | if ((post_div == 5) || |
438 | (post_div == 7) || | 516 | (post_div == 7) || |
439 | (post_div == 9) || | 517 | (post_div == 9) || |
@@ -466,10 +544,10 @@ void radeon_compute_pll(struct radeon_pll *pll, | |||
466 | tmp = (uint64_t)pll->reference_freq * feedback_div; | 544 | tmp = (uint64_t)pll->reference_freq * feedback_div; |
467 | vco = radeon_div(tmp, ref_div); | 545 | vco = radeon_div(tmp, ref_div); |
468 | 546 | ||
469 | if (vco < pll->pll_out_min) { | 547 | if (vco < pll_out_min) { |
470 | min_feed_div = feedback_div + 1; | 548 | min_feed_div = feedback_div + 1; |
471 | continue; | 549 | continue; |
472 | } else if (vco > pll->pll_out_max) { | 550 | } else if (vco > pll_out_max) { |
473 | max_feed_div = feedback_div; | 551 | max_feed_div = feedback_div; |
474 | continue; | 552 | continue; |
475 | } | 553 | } |
@@ -480,7 +558,7 @@ void radeon_compute_pll(struct radeon_pll *pll, | |||
480 | tmp += (uint64_t)pll->reference_freq * 1000 * frac_feedback_div; | 558 | tmp += (uint64_t)pll->reference_freq * 1000 * frac_feedback_div; |
481 | current_freq = radeon_div(tmp, ref_div * post_div); | 559 | current_freq = radeon_div(tmp, ref_div * post_div); |
482 | 560 | ||
483 | if (flags & RADEON_PLL_PREFER_CLOSEST_LOWER) { | 561 | if (pll->flags & RADEON_PLL_PREFER_CLOSEST_LOWER) { |
484 | error = freq - current_freq; | 562 | error = freq - current_freq; |
485 | error = error < 0 ? 0xffffffff : error; | 563 | error = error < 0 ? 0xffffffff : error; |
486 | } else | 564 | } else |
@@ -507,12 +585,12 @@ void radeon_compute_pll(struct radeon_pll *pll, | |||
507 | best_freq = current_freq; | 585 | best_freq = current_freq; |
508 | best_error = error; | 586 | best_error = error; |
509 | best_vco_diff = vco_diff; | 587 | best_vco_diff = vco_diff; |
510 | } else if (((flags & RADEON_PLL_PREFER_LOW_REF_DIV) && (ref_div < best_ref_div)) || | 588 | } else if (((pll->flags & RADEON_PLL_PREFER_LOW_REF_DIV) && (ref_div < best_ref_div)) || |
511 | ((flags & RADEON_PLL_PREFER_HIGH_REF_DIV) && (ref_div > best_ref_div)) || | 589 | ((pll->flags & RADEON_PLL_PREFER_HIGH_REF_DIV) && (ref_div > best_ref_div)) || |
512 | ((flags & RADEON_PLL_PREFER_LOW_FB_DIV) && (feedback_div < best_feedback_div)) || | 590 | ((pll->flags & RADEON_PLL_PREFER_LOW_FB_DIV) && (feedback_div < best_feedback_div)) || |
513 | ((flags & RADEON_PLL_PREFER_HIGH_FB_DIV) && (feedback_div > best_feedback_div)) || | 591 | ((pll->flags & RADEON_PLL_PREFER_HIGH_FB_DIV) && (feedback_div > best_feedback_div)) || |
514 | ((flags & RADEON_PLL_PREFER_LOW_POST_DIV) && (post_div < best_post_div)) || | 592 | ((pll->flags & RADEON_PLL_PREFER_LOW_POST_DIV) && (post_div < best_post_div)) || |
515 | ((flags & RADEON_PLL_PREFER_HIGH_POST_DIV) && (post_div > best_post_div))) { | 593 | ((pll->flags & RADEON_PLL_PREFER_HIGH_POST_DIV) && (post_div > best_post_div))) { |
516 | best_post_div = post_div; | 594 | best_post_div = post_div; |
517 | best_ref_div = ref_div; | 595 | best_ref_div = ref_div; |
518 | best_feedback_div = feedback_div; | 596 | best_feedback_div = feedback_div; |
@@ -542,6 +620,214 @@ void radeon_compute_pll(struct radeon_pll *pll, | |||
542 | *post_div_p = best_post_div; | 620 | *post_div_p = best_post_div; |
543 | } | 621 | } |
544 | 622 | ||
623 | static bool | ||
624 | calc_fb_div(struct radeon_pll *pll, | ||
625 | uint32_t freq, | ||
626 | uint32_t post_div, | ||
627 | uint32_t ref_div, | ||
628 | uint32_t *fb_div, | ||
629 | uint32_t *fb_div_frac) | ||
630 | { | ||
631 | fixed20_12 feedback_divider, a, b; | ||
632 | u32 vco_freq; | ||
633 | |||
634 | vco_freq = freq * post_div; | ||
635 | /* feedback_divider = vco_freq * ref_div / pll->reference_freq; */ | ||
636 | a.full = rfixed_const(pll->reference_freq); | ||
637 | feedback_divider.full = rfixed_const(vco_freq); | ||
638 | feedback_divider.full = rfixed_div(feedback_divider, a); | ||
639 | a.full = rfixed_const(ref_div); | ||
640 | feedback_divider.full = rfixed_mul(feedback_divider, a); | ||
641 | |||
642 | if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) { | ||
643 | /* feedback_divider = floor((feedback_divider * 10.0) + 0.5) * 0.1; */ | ||
644 | a.full = rfixed_const(10); | ||
645 | feedback_divider.full = rfixed_mul(feedback_divider, a); | ||
646 | feedback_divider.full += rfixed_const_half(0); | ||
647 | feedback_divider.full = rfixed_floor(feedback_divider); | ||
648 | feedback_divider.full = rfixed_div(feedback_divider, a); | ||
649 | |||
650 | /* *fb_div = floor(feedback_divider); */ | ||
651 | a.full = rfixed_floor(feedback_divider); | ||
652 | *fb_div = rfixed_trunc(a); | ||
653 | /* *fb_div_frac = fmod(feedback_divider, 1.0) * 10.0; */ | ||
654 | a.full = rfixed_const(10); | ||
655 | b.full = rfixed_mul(feedback_divider, a); | ||
656 | |||
657 | feedback_divider.full = rfixed_floor(feedback_divider); | ||
658 | feedback_divider.full = rfixed_mul(feedback_divider, a); | ||
659 | feedback_divider.full = b.full - feedback_divider.full; | ||
660 | *fb_div_frac = rfixed_trunc(feedback_divider); | ||
661 | } else { | ||
662 | /* *fb_div = floor(feedback_divider + 0.5); */ | ||
663 | feedback_divider.full += rfixed_const_half(0); | ||
664 | feedback_divider.full = rfixed_floor(feedback_divider); | ||
665 | |||
666 | *fb_div = rfixed_trunc(feedback_divider); | ||
667 | *fb_div_frac = 0; | ||
668 | } | ||
669 | |||
670 | if (((*fb_div) < pll->min_feedback_div) || ((*fb_div) > pll->max_feedback_div)) | ||
671 | return false; | ||
672 | else | ||
673 | return true; | ||
674 | } | ||
675 | |||
676 | static bool | ||
677 | calc_fb_ref_div(struct radeon_pll *pll, | ||
678 | uint32_t freq, | ||
679 | uint32_t post_div, | ||
680 | uint32_t *fb_div, | ||
681 | uint32_t *fb_div_frac, | ||
682 | uint32_t *ref_div) | ||
683 | { | ||
684 | fixed20_12 ffreq, max_error, error, pll_out, a; | ||
685 | u32 vco; | ||
686 | u32 pll_out_min, pll_out_max; | ||
687 | |||
688 | if (pll->flags & RADEON_PLL_IS_LCD) { | ||
689 | pll_out_min = pll->lcd_pll_out_min; | ||
690 | pll_out_max = pll->lcd_pll_out_max; | ||
691 | } else { | ||
692 | pll_out_min = pll->pll_out_min; | ||
693 | pll_out_max = pll->pll_out_max; | ||
694 | } | ||
695 | |||
696 | ffreq.full = rfixed_const(freq); | ||
697 | /* max_error = ffreq * 0.0025; */ | ||
698 | a.full = rfixed_const(400); | ||
699 | max_error.full = rfixed_div(ffreq, a); | ||
700 | |||
701 | for ((*ref_div) = pll->min_ref_div; (*ref_div) < pll->max_ref_div; ++(*ref_div)) { | ||
702 | if (calc_fb_div(pll, freq, post_div, (*ref_div), fb_div, fb_div_frac)) { | ||
703 | vco = pll->reference_freq * (((*fb_div) * 10) + (*fb_div_frac)); | ||
704 | vco = vco / ((*ref_div) * 10); | ||
705 | |||
706 | if ((vco < pll_out_min) || (vco > pll_out_max)) | ||
707 | continue; | ||
708 | |||
709 | /* pll_out = vco / post_div; */ | ||
710 | a.full = rfixed_const(post_div); | ||
711 | pll_out.full = rfixed_const(vco); | ||
712 | pll_out.full = rfixed_div(pll_out, a); | ||
713 | |||
714 | if (pll_out.full >= ffreq.full) { | ||
715 | error.full = pll_out.full - ffreq.full; | ||
716 | if (error.full <= max_error.full) | ||
717 | return true; | ||
718 | } | ||
719 | } | ||
720 | } | ||
721 | return false; | ||
722 | } | ||
723 | |||
724 | static void radeon_compute_pll_new(struct radeon_pll *pll, | ||
725 | uint64_t freq, | ||
726 | uint32_t *dot_clock_p, | ||
727 | uint32_t *fb_div_p, | ||
728 | uint32_t *frac_fb_div_p, | ||
729 | uint32_t *ref_div_p, | ||
730 | uint32_t *post_div_p) | ||
731 | { | ||
732 | u32 fb_div = 0, fb_div_frac = 0, post_div = 0, ref_div = 0; | ||
733 | u32 best_freq = 0, vco_frequency; | ||
734 | u32 pll_out_min, pll_out_max; | ||
735 | |||
736 | if (pll->flags & RADEON_PLL_IS_LCD) { | ||
737 | pll_out_min = pll->lcd_pll_out_min; | ||
738 | pll_out_max = pll->lcd_pll_out_max; | ||
739 | } else { | ||
740 | pll_out_min = pll->pll_out_min; | ||
741 | pll_out_max = pll->pll_out_max; | ||
742 | } | ||
743 | |||
744 | /* freq = freq / 10; */ | ||
745 | do_div(freq, 10); | ||
746 | |||
747 | if (pll->flags & RADEON_PLL_USE_POST_DIV) { | ||
748 | post_div = pll->post_div; | ||
749 | if ((post_div < pll->min_post_div) || (post_div > pll->max_post_div)) | ||
750 | goto done; | ||
751 | |||
752 | vco_frequency = freq * post_div; | ||
753 | if ((vco_frequency < pll_out_min) || (vco_frequency > pll_out_max)) | ||
754 | goto done; | ||
755 | |||
756 | if (pll->flags & RADEON_PLL_USE_REF_DIV) { | ||
757 | ref_div = pll->reference_div; | ||
758 | if ((ref_div < pll->min_ref_div) || (ref_div > pll->max_ref_div)) | ||
759 | goto done; | ||
760 | if (!calc_fb_div(pll, freq, post_div, ref_div, &fb_div, &fb_div_frac)) | ||
761 | goto done; | ||
762 | } | ||
763 | } else { | ||
764 | for (post_div = pll->max_post_div; post_div >= pll->min_post_div; --post_div) { | ||
765 | if (pll->flags & RADEON_PLL_LEGACY) { | ||
766 | if ((post_div == 5) || | ||
767 | (post_div == 7) || | ||
768 | (post_div == 9) || | ||
769 | (post_div == 10) || | ||
770 | (post_div == 11)) | ||
771 | continue; | ||
772 | } | ||
773 | |||
774 | if ((pll->flags & RADEON_PLL_NO_ODD_POST_DIV) && (post_div & 1)) | ||
775 | continue; | ||
776 | |||
777 | vco_frequency = freq * post_div; | ||
778 | if ((vco_frequency < pll_out_min) || (vco_frequency > pll_out_max)) | ||
779 | continue; | ||
780 | if (pll->flags & RADEON_PLL_USE_REF_DIV) { | ||
781 | ref_div = pll->reference_div; | ||
782 | if ((ref_div < pll->min_ref_div) || (ref_div > pll->max_ref_div)) | ||
783 | goto done; | ||
784 | if (calc_fb_div(pll, freq, post_div, ref_div, &fb_div, &fb_div_frac)) | ||
785 | break; | ||
786 | } else { | ||
787 | if (calc_fb_ref_div(pll, freq, post_div, &fb_div, &fb_div_frac, &ref_div)) | ||
788 | break; | ||
789 | } | ||
790 | } | ||
791 | } | ||
792 | |||
793 | best_freq = pll->reference_freq * 10 * fb_div; | ||
794 | best_freq += pll->reference_freq * fb_div_frac; | ||
795 | best_freq = best_freq / (ref_div * post_div); | ||
796 | |||
797 | done: | ||
798 | if (best_freq == 0) | ||
799 | DRM_ERROR("Couldn't find valid PLL dividers\n"); | ||
800 | |||
801 | *dot_clock_p = best_freq / 10; | ||
802 | *fb_div_p = fb_div; | ||
803 | *frac_fb_div_p = fb_div_frac; | ||
804 | *ref_div_p = ref_div; | ||
805 | *post_div_p = post_div; | ||
806 | |||
807 | DRM_DEBUG("%u %d.%d, %d, %d\n", *dot_clock_p, *fb_div_p, *frac_fb_div_p, *ref_div_p, *post_div_p); | ||
808 | } | ||
809 | |||
810 | void radeon_compute_pll(struct radeon_pll *pll, | ||
811 | uint64_t freq, | ||
812 | uint32_t *dot_clock_p, | ||
813 | uint32_t *fb_div_p, | ||
814 | uint32_t *frac_fb_div_p, | ||
815 | uint32_t *ref_div_p, | ||
816 | uint32_t *post_div_p) | ||
817 | { | ||
818 | switch (pll->algo) { | ||
819 | case PLL_ALGO_NEW: | ||
820 | radeon_compute_pll_new(pll, freq, dot_clock_p, fb_div_p, | ||
821 | frac_fb_div_p, ref_div_p, post_div_p); | ||
822 | break; | ||
823 | case PLL_ALGO_LEGACY: | ||
824 | default: | ||
825 | radeon_compute_pll_legacy(pll, freq, dot_clock_p, fb_div_p, | ||
826 | frac_fb_div_p, ref_div_p, post_div_p); | ||
827 | break; | ||
828 | } | ||
829 | } | ||
830 | |||
545 | static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb) | 831 | static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb) |
546 | { | 832 | { |
547 | struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb); | 833 | struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb); |
@@ -550,12 +836,8 @@ static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb) | |||
550 | if (fb->fbdev) | 836 | if (fb->fbdev) |
551 | radeonfb_remove(dev, fb); | 837 | radeonfb_remove(dev, fb); |
552 | 838 | ||
553 | if (radeon_fb->obj) { | 839 | if (radeon_fb->obj) |
554 | radeon_gem_object_unpin(radeon_fb->obj); | 840 | drm_gem_object_unreference_unlocked(radeon_fb->obj); |
555 | mutex_lock(&dev->struct_mutex); | ||
556 | drm_gem_object_unreference(radeon_fb->obj); | ||
557 | mutex_unlock(&dev->struct_mutex); | ||
558 | } | ||
559 | drm_framebuffer_cleanup(fb); | 841 | drm_framebuffer_cleanup(fb); |
560 | kfree(radeon_fb); | 842 | kfree(radeon_fb); |
561 | } | 843 | } |
@@ -599,7 +881,11 @@ radeon_user_framebuffer_create(struct drm_device *dev, | |||
599 | struct drm_gem_object *obj; | 881 | struct drm_gem_object *obj; |
600 | 882 | ||
601 | obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle); | 883 | obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle); |
602 | 884 | if (obj == NULL) { | |
885 | dev_err(&dev->pdev->dev, "No GEM object associated to handle 0x%08X, " | ||
886 | "can't create framebuffer\n", mode_cmd->handle); | ||
887 | return NULL; | ||
888 | } | ||
603 | return radeon_framebuffer_create(dev, mode_cmd, obj); | 889 | return radeon_framebuffer_create(dev, mode_cmd, obj); |
604 | } | 890 | } |
605 | 891 | ||
@@ -629,7 +915,7 @@ static struct drm_prop_enum_list radeon_tv_std_enum_list[] = | |||
629 | { TV_STD_SECAM, "secam" }, | 915 | { TV_STD_SECAM, "secam" }, |
630 | }; | 916 | }; |
631 | 917 | ||
632 | int radeon_modeset_create_props(struct radeon_device *rdev) | 918 | static int radeon_modeset_create_props(struct radeon_device *rdev) |
633 | { | 919 | { |
634 | int i, sz; | 920 | int i, sz; |
635 | 921 | ||
@@ -642,7 +928,7 @@ int radeon_modeset_create_props(struct radeon_device *rdev) | |||
642 | return -ENOMEM; | 928 | return -ENOMEM; |
643 | 929 | ||
644 | rdev->mode_info.coherent_mode_property->values[0] = 0; | 930 | rdev->mode_info.coherent_mode_property->values[0] = 0; |
645 | rdev->mode_info.coherent_mode_property->values[0] = 1; | 931 | rdev->mode_info.coherent_mode_property->values[1] = 1; |
646 | } | 932 | } |
647 | 933 | ||
648 | if (!ASIC_IS_AVIVO(rdev)) { | 934 | if (!ASIC_IS_AVIVO(rdev)) { |
@@ -666,7 +952,7 @@ int radeon_modeset_create_props(struct radeon_device *rdev) | |||
666 | if (!rdev->mode_info.load_detect_property) | 952 | if (!rdev->mode_info.load_detect_property) |
667 | return -ENOMEM; | 953 | return -ENOMEM; |
668 | rdev->mode_info.load_detect_property->values[0] = 0; | 954 | rdev->mode_info.load_detect_property->values[0] = 0; |
669 | rdev->mode_info.load_detect_property->values[0] = 1; | 955 | rdev->mode_info.load_detect_property->values[1] = 1; |
670 | 956 | ||
671 | drm_mode_create_scaling_mode_property(rdev->ddev); | 957 | drm_mode_create_scaling_mode_property(rdev->ddev); |
672 | 958 | ||
@@ -685,9 +971,26 @@ int radeon_modeset_create_props(struct radeon_device *rdev) | |||
685 | return 0; | 971 | return 0; |
686 | } | 972 | } |
687 | 973 | ||
974 | void radeon_update_display_priority(struct radeon_device *rdev) | ||
975 | { | ||
976 | /* adjustment options for the display watermarks */ | ||
977 | if ((radeon_disp_priority == 0) || (radeon_disp_priority > 2)) { | ||
978 | /* set display priority to high for r3xx, rv515 chips | ||
979 | * this avoids flickering due to underflow to the | ||
980 | * display controllers during heavy acceleration. | ||
981 | */ | ||
982 | if (ASIC_IS_R300(rdev) || (rdev->family == CHIP_RV515)) | ||
983 | rdev->disp_priority = 2; | ||
984 | else | ||
985 | rdev->disp_priority = 0; | ||
986 | } else | ||
987 | rdev->disp_priority = radeon_disp_priority; | ||
988 | |||
989 | } | ||
990 | |||
688 | int radeon_modeset_init(struct radeon_device *rdev) | 991 | int radeon_modeset_init(struct radeon_device *rdev) |
689 | { | 992 | { |
690 | int num_crtc = 2, i; | 993 | int i; |
691 | int ret; | 994 | int ret; |
692 | 995 | ||
693 | drm_mode_config_init(rdev->ddev); | 996 | drm_mode_config_init(rdev->ddev); |
@@ -710,11 +1013,14 @@ int radeon_modeset_init(struct radeon_device *rdev) | |||
710 | return ret; | 1013 | return ret; |
711 | } | 1014 | } |
712 | 1015 | ||
713 | if (rdev->flags & RADEON_SINGLE_CRTC) | 1016 | /* check combios for a valid hardcoded EDID - Sun servers */ |
714 | num_crtc = 1; | 1017 | if (!rdev->is_atom_bios) { |
1018 | /* check for hardcoded EDID in BIOS */ | ||
1019 | radeon_combios_check_hardcoded_edid(rdev); | ||
1020 | } | ||
715 | 1021 | ||
716 | /* allocate crtcs */ | 1022 | /* allocate crtcs */ |
717 | for (i = 0; i < num_crtc; i++) { | 1023 | for (i = 0; i < rdev->num_crtc; i++) { |
718 | radeon_crtc_init(rdev->ddev, i); | 1024 | radeon_crtc_init(rdev->ddev, i); |
719 | } | 1025 | } |
720 | 1026 | ||
@@ -723,13 +1029,18 @@ int radeon_modeset_init(struct radeon_device *rdev) | |||
723 | if (!ret) { | 1029 | if (!ret) { |
724 | return ret; | 1030 | return ret; |
725 | } | 1031 | } |
1032 | /* initialize hpd */ | ||
1033 | radeon_hpd_init(rdev); | ||
726 | drm_helper_initial_config(rdev->ddev); | 1034 | drm_helper_initial_config(rdev->ddev); |
727 | return 0; | 1035 | return 0; |
728 | } | 1036 | } |
729 | 1037 | ||
730 | void radeon_modeset_fini(struct radeon_device *rdev) | 1038 | void radeon_modeset_fini(struct radeon_device *rdev) |
731 | { | 1039 | { |
1040 | kfree(rdev->mode_info.bios_hardcoded_edid); | ||
1041 | |||
732 | if (rdev->mode_info.mode_config_initialized) { | 1042 | if (rdev->mode_info.mode_config_initialized) { |
1043 | radeon_hpd_fini(rdev); | ||
733 | drm_mode_config_cleanup(rdev->ddev); | 1044 | drm_mode_config_cleanup(rdev->ddev); |
734 | rdev->mode_info.mode_config_initialized = false; | 1045 | rdev->mode_info.mode_config_initialized = false; |
735 | } | 1046 | } |
@@ -750,9 +1061,17 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc, | |||
750 | if (encoder->crtc != crtc) | 1061 | if (encoder->crtc != crtc) |
751 | continue; | 1062 | continue; |
752 | if (first) { | 1063 | if (first) { |
753 | radeon_crtc->rmx_type = radeon_encoder->rmx_type; | 1064 | /* set scaling */ |
1065 | if (radeon_encoder->rmx_type == RMX_OFF) | ||
1066 | radeon_crtc->rmx_type = RMX_OFF; | ||
1067 | else if (mode->hdisplay < radeon_encoder->native_mode.hdisplay || | ||
1068 | mode->vdisplay < radeon_encoder->native_mode.vdisplay) | ||
1069 | radeon_crtc->rmx_type = radeon_encoder->rmx_type; | ||
1070 | else | ||
1071 | radeon_crtc->rmx_type = RMX_OFF; | ||
1072 | /* copy native mode */ | ||
754 | memcpy(&radeon_crtc->native_mode, | 1073 | memcpy(&radeon_crtc->native_mode, |
755 | &radeon_encoder->native_mode, | 1074 | &radeon_encoder->native_mode, |
756 | sizeof(struct drm_display_mode)); | 1075 | sizeof(struct drm_display_mode)); |
757 | first = false; | 1076 | first = false; |
758 | } else { | 1077 | } else { |