Rev 3764 | Rev 5271 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 3764 | Rev 5078 | ||
---|---|---|---|
Line 31... | Line 31... | ||
31 | #include |
31 | #include |
Line 32... | Line 32... | ||
32 | 32 | ||
33 | #include |
33 | #include |
Line -... | Line 34... | ||
- | 34 | #include |
|
- | 35 | ||
- | 36 | /* Greatest common divisor */ |
|
- | 37 | unsigned long gcd(unsigned long a, unsigned long b) |
|
- | 38 | { |
|
- | 39 | unsigned long r; |
|
- | 40 | ||
- | 41 | if (a < b) |
|
- | 42 | swap(a, b); |
|
- | 43 | ||
- | 44 | if (!b) |
|
- | 45 | return a; |
|
- | 46 | while ((r = a % b) != 0) { |
|
- | 47 | a = b; |
|
- | 48 | b = r; |
|
- | 49 | } |
|
- | 50 | return b; |
|
34 | #include |
51 | } |
35 | 52 | ||
36 | static void avivo_crtc_load_lut(struct drm_crtc *crtc) |
53 | static void avivo_crtc_load_lut(struct drm_crtc *crtc) |
37 | { |
54 | { |
38 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
55 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
Line 61... | Line 78... | ||
61 | (radeon_crtc->lut_r[i] << 20) | |
78 | (radeon_crtc->lut_r[i] << 20) | |
62 | (radeon_crtc->lut_g[i] << 10) | |
79 | (radeon_crtc->lut_g[i] << 10) | |
63 | (radeon_crtc->lut_b[i] << 0)); |
80 | (radeon_crtc->lut_b[i] << 0)); |
64 | } |
81 | } |
Line -... | Line 82... | ||
- | 82 | ||
65 | 83 | /* Only change bit 0 of LUT_SEL, other bits are set elsewhere */ |
|
66 | WREG32(AVIVO_D1GRPH_LUT_SEL + radeon_crtc->crtc_offset, radeon_crtc->crtc_id); |
84 | WREG32_P(AVIVO_D1GRPH_LUT_SEL + radeon_crtc->crtc_offset, radeon_crtc->crtc_id, ~1); |
Line 67... | Line 85... | ||
67 | } |
85 | } |
68 | 86 | ||
69 | static void dce4_crtc_load_lut(struct drm_crtc *crtc) |
87 | static void dce4_crtc_load_lut(struct drm_crtc *crtc) |
Line 151... | Line 169... | ||
151 | WREG32(NI_OUTPUT_CSC_CONTROL + radeon_crtc->crtc_offset, |
169 | WREG32(NI_OUTPUT_CSC_CONTROL + radeon_crtc->crtc_offset, |
152 | (NI_OUTPUT_CSC_GRPH_MODE(NI_OUTPUT_CSC_BYPASS) | |
170 | (NI_OUTPUT_CSC_GRPH_MODE(NI_OUTPUT_CSC_BYPASS) | |
153 | NI_OUTPUT_CSC_OVL_MODE(NI_OUTPUT_CSC_BYPASS))); |
171 | NI_OUTPUT_CSC_OVL_MODE(NI_OUTPUT_CSC_BYPASS))); |
154 | /* XXX match this to the depth of the crtc fmt block, move to modeset? */ |
172 | /* XXX match this to the depth of the crtc fmt block, move to modeset? */ |
155 | WREG32(0x6940 + radeon_crtc->crtc_offset, 0); |
173 | WREG32(0x6940 + radeon_crtc->crtc_offset, 0); |
- | 174 | if (ASIC_IS_DCE8(rdev)) { |
|
- | 175 | /* XXX this only needs to be programmed once per crtc at startup, |
|
- | 176 | * not sure where the best place for it is |
|
- | 177 | */ |
|
- | 178 | WREG32(CIK_ALPHA_CONTROL + radeon_crtc->crtc_offset, |
|
- | 179 | CIK_CURSOR_ALPHA_BLND_ENA); |
|
156 | 180 | } |
|
157 | } |
181 | } |
Line 158... | Line 182... | ||
158 | 182 | ||
159 | static void legacy_crtc_load_lut(struct drm_crtc *crtc) |
183 | static void legacy_crtc_load_lut(struct drm_crtc *crtc) |
160 | { |
184 | { |
Line 241... | Line 265... | ||
241 | 265 | ||
242 | drm_crtc_cleanup(crtc); |
266 | drm_crtc_cleanup(crtc); |
243 | kfree(radeon_crtc); |
267 | kfree(radeon_crtc); |
Line -... | Line 268... | ||
- | 268 | } |
|
- | 269 | ||
- | 270 | static int |
|
- | 271 | radeon_crtc_set_config(struct drm_mode_set *set) |
|
- | 272 | { |
|
- | 273 | struct drm_device *dev; |
|
- | 274 | struct radeon_device *rdev; |
|
- | 275 | struct drm_crtc *crtc; |
|
- | 276 | bool active = false; |
|
- | 277 | int ret; |
|
- | 278 | ||
- | 279 | if (!set || !set->crtc) |
|
- | 280 | return -EINVAL; |
|
- | 281 | ||
- | 282 | dev = set->crtc->dev; |
|
- | 283 | ||
- | 284 | ret = drm_crtc_helper_set_config(set); |
|
- | 285 | ||
- | 286 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) |
|
- | 287 | if (crtc->enabled) |
|
- | 288 | active = true; |
|
- | 289 | ||
- | 290 | // pm_runtime_mark_last_busy(dev->dev); |
|
- | 291 | ||
- | 292 | rdev = dev->dev_private; |
|
- | 293 | /* if we have active crtcs and we don't have a power ref, |
|
- | 294 | take the current one */ |
|
- | 295 | if (active && !rdev->have_disp_power_ref) { |
|
- | 296 | rdev->have_disp_power_ref = true; |
|
- | 297 | return ret; |
|
- | 298 | } |
|
- | 299 | /* if we have no active crtcs, then drop the power ref |
|
- | 300 | we got before */ |
|
- | 301 | if (!active && rdev->have_disp_power_ref) { |
|
- | 302 | // pm_runtime_put_autosuspend(dev->dev); |
|
- | 303 | rdev->have_disp_power_ref = false; |
|
- | 304 | } |
|
- | 305 | ||
- | 306 | /* drop the power reference we got coming in here */ |
|
- | 307 | // pm_runtime_put_autosuspend(dev->dev); |
|
244 | } |
308 | return ret; |
245 | 309 | } |
|
246 | static const struct drm_crtc_funcs radeon_crtc_funcs = { |
310 | static const struct drm_crtc_funcs radeon_crtc_funcs = { |
247 | .cursor_set = NULL, |
311 | .cursor_set = NULL, |
248 | .cursor_move = NULL, |
312 | .cursor_move = NULL, |
249 | .gamma_set = radeon_crtc_gamma_set, |
313 | .gamma_set = radeon_crtc_gamma_set, |
250 | .set_config = drm_crtc_helper_set_config, |
314 | .set_config = radeon_crtc_set_config, |
251 | .destroy = radeon_crtc_destroy, |
315 | .destroy = radeon_crtc_destroy, |
Line 252... | Line 316... | ||
252 | .page_flip = NULL, |
316 | .page_flip = NULL, |
Line 266... | Line 330... | ||
266 | 330 | ||
267 | drm_mode_crtc_set_gamma_size(&radeon_crtc->base, 256); |
331 | drm_mode_crtc_set_gamma_size(&radeon_crtc->base, 256); |
268 | radeon_crtc->crtc_id = index; |
332 | radeon_crtc->crtc_id = index; |
Line -... | Line 333... | ||
- | 333 | rdev->mode_info.crtcs[index] = radeon_crtc; |
|
- | 334 | ||
- | 335 | if (rdev->family >= CHIP_BONAIRE) { |
|
- | 336 | radeon_crtc->max_cursor_width = CIK_CURSOR_WIDTH; |
|
- | 337 | radeon_crtc->max_cursor_height = CIK_CURSOR_HEIGHT; |
|
- | 338 | } else { |
|
- | 339 | radeon_crtc->max_cursor_width = CURSOR_WIDTH; |
|
- | 340 | radeon_crtc->max_cursor_height = CURSOR_HEIGHT; |
|
- | 341 | } |
|
- | 342 | dev->mode_config.cursor_width = radeon_crtc->max_cursor_width; |
|
269 | rdev->mode_info.crtcs[index] = radeon_crtc; |
343 | dev->mode_config.cursor_height = radeon_crtc->max_cursor_height; |
270 | 344 | ||
271 | #if 0 |
345 | #if 0 |
272 | radeon_crtc->mode_set.crtc = &radeon_crtc->base; |
346 | radeon_crtc->mode_set.crtc = &radeon_crtc->base; |
273 | radeon_crtc->mode_set.connectors = (struct drm_connector **)(radeon_crtc + 1); |
347 | radeon_crtc->mode_set.connectors = (struct drm_connector **)(radeon_crtc + 1); |
Line 284... | Line 358... | ||
284 | radeon_atombios_init_crtc(dev, radeon_crtc); |
358 | radeon_atombios_init_crtc(dev, radeon_crtc); |
285 | else |
359 | else |
286 | radeon_legacy_init_crtc(dev, radeon_crtc); |
360 | radeon_legacy_init_crtc(dev, radeon_crtc); |
287 | } |
361 | } |
Line 288... | Line 362... | ||
288 | 362 | ||
289 | static const char *encoder_names[37] = { |
363 | static const char *encoder_names[38] = { |
290 | "NONE", |
364 | "NONE", |
291 | "INTERNAL_LVDS", |
365 | "INTERNAL_LVDS", |
292 | "INTERNAL_TMDS1", |
366 | "INTERNAL_TMDS1", |
293 | "INTERNAL_TMDS2", |
367 | "INTERNAL_TMDS2", |
Line 321... | Line 395... | ||
321 | "INTERNAL_KLDSCP_LVTMA", |
395 | "INTERNAL_KLDSCP_LVTMA", |
322 | "INTERNAL_UNIPHY1", |
396 | "INTERNAL_UNIPHY1", |
323 | "INTERNAL_UNIPHY2", |
397 | "INTERNAL_UNIPHY2", |
324 | "NUTMEG", |
398 | "NUTMEG", |
325 | "TRAVIS", |
399 | "TRAVIS", |
326 | "INTERNAL_VCE" |
400 | "INTERNAL_VCE", |
- | 401 | "INTERNAL_UNIPHY3", |
|
327 | }; |
402 | }; |
Line 328... | Line 403... | ||
328 | 403 | ||
329 | static const char *hpd_names[6] = { |
404 | static const char *hpd_names[6] = { |
330 | "HPD1", |
405 | "HPD1", |
Line 346... | Line 421... | ||
346 | 421 | ||
347 | DRM_INFO("Radeon Display Connectors\n"); |
422 | DRM_INFO("Radeon Display Connectors\n"); |
348 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
423 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
349 | radeon_connector = to_radeon_connector(connector); |
424 | radeon_connector = to_radeon_connector(connector); |
350 | DRM_INFO("Connector %d:\n", i); |
425 | DRM_INFO("Connector %d:\n", i); |
351 | DRM_INFO(" %s\n", drm_get_connector_name(connector)); |
426 | DRM_INFO(" %s\n", connector->name); |
352 | if (radeon_connector->hpd.hpd != RADEON_HPD_NONE) |
427 | if (radeon_connector->hpd.hpd != RADEON_HPD_NONE) |
353 | DRM_INFO(" %s\n", hpd_names[radeon_connector->hpd.hpd]); |
428 | DRM_INFO(" %s\n", hpd_names[radeon_connector->hpd.hpd]); |
354 | if (radeon_connector->ddc_bus) { |
429 | if (radeon_connector->ddc_bus) { |
355 | DRM_INFO(" DDC: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", |
430 | DRM_INFO(" DDC: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", |
Line 436... | Line 511... | ||
436 | } |
511 | } |
Line 437... | Line 512... | ||
437 | 512 | ||
438 | return ret; |
513 | return ret; |
Line -... | Line 514... | ||
- | 514 | } |
|
- | 515 | ||
- | 516 | /* avivo */ |
|
- | 517 | ||
- | 518 | /** |
|
- | 519 | * avivo_reduce_ratio - fractional number reduction |
|
- | 520 | * |
|
- | 521 | * @nom: nominator |
|
- | 522 | * @den: denominator |
|
- | 523 | * @nom_min: minimum value for nominator |
|
- | 524 | * @den_min: minimum value for denominator |
|
439 | } |
525 | * |
- | 526 | * Find the greatest common divisor and apply it on both nominator and |
|
- | 527 | * denominator, but make nominator and denominator are at least as large |
|
- | 528 | * as their minimum values. |
|
- | 529 | */ |
|
440 | 530 | static void avivo_reduce_ratio(unsigned *nom, unsigned *den, |
|
441 | int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) |
- | |
442 | { |
- | |
443 | struct drm_device *dev = radeon_connector->base.dev; |
531 | unsigned nom_min, unsigned den_min) |
Line 444... | Line 532... | ||
444 | struct radeon_device *rdev = dev->dev_private; |
532 | { |
445 | int ret = 0; |
533 | unsigned tmp; |
- | 534 | ||
446 | 535 | /* reduce the numbers to a simpler ratio */ |
|
Line 447... | Line 536... | ||
447 | /* on hw with routers, select right port */ |
536 | tmp = gcd(*nom, *den); |
448 | if (radeon_connector->router.ddc_valid) |
537 | *nom /= tmp; |
449 | radeon_router_select_ddc_port(radeon_connector); |
538 | *den /= tmp; |
450 | - | ||
451 | if (radeon_connector_encoder_get_dp_bridge_encoder_id(&radeon_connector->base) != |
539 | |
452 | ENCODER_OBJECT_ID_NONE) { |
- | |
453 | struct radeon_connector_atom_dig *dig = radeon_connector->con_priv; |
- | |
454 | - | ||
455 | if (dig->dp_i2c_bus) |
- | |
456 | radeon_connector->edid = drm_get_edid(&radeon_connector->base, |
- | |
457 | &dig->dp_i2c_bus->adapter); |
- | |
458 | } else if ((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) || |
- | |
459 | (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP)) { |
- | |
460 | struct radeon_connector_atom_dig *dig = radeon_connector->con_priv; |
- | |
461 | - | ||
462 | if ((dig->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT || |
- | |
463 | dig->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) && dig->dp_i2c_bus) |
- | |
464 | radeon_connector->edid = drm_get_edid(&radeon_connector->base, |
- | |
465 | &dig->dp_i2c_bus->adapter); |
540 | /* make sure nominator is large enough */ |
466 | else if (radeon_connector->ddc_bus && !radeon_connector->edid) |
- | |
467 | radeon_connector->edid = drm_get_edid(&radeon_connector->base, |
- | |
468 | &radeon_connector->ddc_bus->adapter); |
- | |
469 | } else { |
541 | if (*nom < nom_min) { |
Line 470... | Line 542... | ||
470 | if (radeon_connector->ddc_bus && !radeon_connector->edid) |
542 | tmp = DIV_ROUND_UP(nom_min, *nom); |
471 | radeon_connector->edid = drm_get_edid(&radeon_connector->base, |
543 | *nom *= tmp; |
472 | &radeon_connector->ddc_bus->adapter); |
- | |
473 | } |
- | |
474 | - | ||
475 | if (!radeon_connector->edid) { |
544 | *den *= tmp; |
476 | if (rdev->is_atom_bios) { |
545 | } |
477 | /* some laptops provide a hardcoded edid in rom for LCDs */ |
- | |
478 | if (((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_LVDS) || |
546 | |
479 | (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP))) |
547 | /* make sure the denominator is large enough */ |
480 | radeon_connector->edid = radeon_bios_get_hardcoded_edid(rdev); |
- | |
481 | } else |
- | |
482 | /* some servers provide a hardcoded edid in rom for KVMs */ |
- | |
483 | radeon_connector->edid = radeon_bios_get_hardcoded_edid(rdev); |
- | |
484 | } |
- | |
485 | if (radeon_connector->edid) { |
- | |
486 | drm_mode_connector_update_edid_property(&radeon_connector->base, radeon_connector->edid); |
- | |
487 | ret = drm_add_edid_modes(&radeon_connector->base, radeon_connector->edid); |
548 | if (*den < den_min) { |
Line 488... | Line 549... | ||
488 | return ret; |
549 | tmp = DIV_ROUND_UP(den_min, *den); |
489 | } |
550 | *nom *= tmp; |
- | 551 | *den *= tmp; |
|
- | 552 | } |
|
490 | drm_mode_connector_update_edid_property(&radeon_connector->base, NULL); |
553 | } |
491 | return 0; |
554 | |
- | 555 | /** |
|
- | 556 | * avivo_get_fb_ref_div - feedback and ref divider calculation |
|
- | 557 | * |
|
- | 558 | * @nom: nominator |
|
- | 559 | * @den: denominator |
|
- | 560 | * @post_div: post divider |
|
492 | } |
561 | * @fb_div_max: feedback divider maximum |
- | 562 | * @ref_div_max: reference divider maximum |
|
- | 563 | * @fb_div: resulting feedback divider |
|
493 | 564 | * @ref_div: resulting reference divider |
|
494 | /* avivo */ |
565 | * |
495 | static void avivo_get_fb_div(struct radeon_pll *pll, |
566 | * Calculate feedback and reference divider for a given post divider. Makes |
- | 567 | * sure we stay within the limits. |
|
496 | u32 target_clock, |
568 | */ |
Line 497... | Line 569... | ||
497 | u32 post_div, |
569 | static void avivo_get_fb_ref_div(unsigned nom, unsigned den, unsigned post_div, |
498 | u32 ref_div, |
570 | unsigned fb_div_max, unsigned ref_div_max, |
499 | u32 *fb_div, |
571 | unsigned *fb_div, unsigned *ref_div) |
Line 500... | Line 572... | ||
500 | u32 *frac_fb_div) |
572 | { |
501 | { |
573 | /* limit reference * post divider to a maximum */ |
502 | u32 tmp = post_div * ref_div; |
574 | ref_div_max = max(min(100 / post_div, ref_div_max), 1u); |
503 | 575 | ||
- | 576 | /* get matching reference and feedback divider */ |
|
504 | tmp *= target_clock; |
577 | *ref_div = min(max(DIV_ROUND_CLOSEST(den, post_div), 1u), ref_div_max); |
Line -... | Line 578... | ||
- | 578 | *fb_div = DIV_ROUND_CLOSEST(nom * *ref_div * post_div, den); |
|
- | 579 | ||
- | 580 | /* limit fb divider to its maximum */ |
|
- | 581 | if (*fb_div > fb_div_max) { |
|
- | 582 | *ref_div = DIV_ROUND_CLOSEST(*ref_div * fb_div_max, *fb_div); |
|
- | 583 | *fb_div = fb_div_max; |
|
- | 584 | } |
|
- | 585 | } |
|
- | 586 | ||
- | 587 | /** |
|
- | 588 | * radeon_compute_pll_avivo - compute PLL paramaters |
|
- | 589 | * |
|
- | 590 | * @pll: information about the PLL |
|
505 | *fb_div = tmp / pll->reference_freq; |
591 | * @dot_clock_p: resulting pixel clock |
- | 592 | * fb_div_p: resulting feedback divider |
|
506 | *frac_fb_div = tmp % pll->reference_freq; |
593 | * frac_fb_div_p: fractional part of the feedback divider |
- | 594 | * ref_div_p: resulting reference divider |
|
- | 595 | * post_div_p: resulting reference divider |
|
- | 596 | * |
|
- | 597 | * Try to calculate the PLL parameters to generate the given frequency: |
|
507 | 598 | * dot_clock = (ref_freq * feedback_div) / (ref_div * post_div) |
|
- | 599 | */ |
|
508 | if (*fb_div > pll->max_feedback_div) |
600 | void radeon_compute_pll_avivo(struct radeon_pll *pll, |
Line 509... | Line 601... | ||
509 | *fb_div = pll->max_feedback_div; |
601 | u32 freq, |
- | 602 | u32 *dot_clock_p, |
|
- | 603 | u32 *fb_div_p, |
|
- | 604 | u32 *frac_fb_div_p, |
|
- | 605 | u32 *ref_div_p, |
|
- | 606 | u32 *post_div_p) |
|
- | 607 | { |
|
510 | else if (*fb_div < pll->min_feedback_div) |
608 | unsigned target_clock = pll->flags & RADEON_PLL_USE_FRAC_FB_DIV ? |
- | 609 | freq : freq / 10; |
|
Line 511... | Line 610... | ||
511 | *fb_div = pll->min_feedback_div; |
610 | |
- | 611 | unsigned fb_div_min, fb_div_max, fb_div; |
|
- | 612 | unsigned post_div_min, post_div_max, post_div; |
|
- | 613 | unsigned ref_div_min, ref_div_max, ref_div; |
|
- | 614 | unsigned post_div_best, diff_best; |
|
- | 615 | unsigned nom, den; |
|
512 | } |
616 | |
513 | 617 | /* determine allowed feedback divider range */ |
|
514 | static u32 avivo_get_post_div(struct radeon_pll *pll, |
618 | fb_div_min = pll->min_feedback_div; |
515 | u32 target_clock) |
619 | fb_div_max = pll->max_feedback_div; |
516 | { |
620 | |
- | 621 | if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) { |
|
517 | u32 vco, post_div, tmp; |
622 | fb_div_min *= 10; |
518 | 623 | fb_div_max *= 10; |
|
519 | if (pll->flags & RADEON_PLL_USE_POST_DIV) |
624 | } |
520 | return pll->post_div; |
625 | |
521 | - | ||
Line -... | Line 626... | ||
- | 626 | /* determine allowed ref divider range */ |
|
- | 627 | if (pll->flags & RADEON_PLL_USE_REF_DIV) |
|
- | 628 | ref_div_min = pll->reference_div; |
|
522 | if (pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP) { |
629 | else |
- | 630 | ref_div_min = pll->min_ref_div; |
|
523 | if (pll->flags & RADEON_PLL_IS_LCD) |
631 | |
Line 524... | Line 632... | ||
524 | vco = pll->lcd_pll_out_min; |
632 | if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV && |
525 | else |
633 | pll->flags & RADEON_PLL_USE_REF_DIV) |
526 | vco = pll->pll_out_min; |
634 | ref_div_max = pll->reference_div; |
527 | } else { |
635 | else |
- | 636 | ref_div_max = pll->max_ref_div; |
|
- | 637 | ||
- | 638 | /* determine allowed post divider range */ |
|
- | 639 | if (pll->flags & RADEON_PLL_USE_POST_DIV) { |
|
- | 640 | post_div_min = pll->post_div; |
|
528 | if (pll->flags & RADEON_PLL_IS_LCD) |
641 | post_div_max = pll->post_div; |
529 | vco = pll->lcd_pll_out_max; |
642 | } else { |
530 | else |
643 | unsigned vco_min, vco_max; |
Line -... | Line 644... | ||
- | 644 | ||
531 | vco = pll->pll_out_max; |
645 | if (pll->flags & RADEON_PLL_IS_LCD) { |
532 | } |
646 | vco_min = pll->lcd_pll_out_min; |
533 | 647 | vco_max = pll->lcd_pll_out_max; |
|
534 | post_div = vco / target_clock; |
648 | } else { |
Line -... | Line 649... | ||
- | 649 | vco_min = pll->pll_out_min; |
|
- | 650 | vco_max = pll->pll_out_max; |
|
535 | tmp = vco % target_clock; |
651 | } |
- | 652 | ||
- | 653 | if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) { |
|
536 | 654 | vco_min *= 10; |
|
Line -... | Line 655... | ||
- | 655 | vco_max *= 10; |
|
- | 656 | } |
|
537 | if (pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP) { |
657 | |
Line 538... | Line 658... | ||
538 | if (tmp) |
658 | post_div_min = vco_min / target_clock; |
539 | post_div++; |
- | |
540 | } else { |
- | |
541 | if (!tmp) |
- | |
542 | post_div--; |
- | |
543 | } |
- | |
544 | - | ||
545 | if (post_div > pll->max_post_div) |
- | |
546 | post_div = pll->max_post_div; |
- | |
547 | else if (post_div < pll->min_post_div) |
659 | if ((target_clock * post_div_min) < vco_min) |
548 | post_div = pll->min_post_div; |
- | |
549 | - | ||
Line -... | Line 660... | ||
- | 660 | ++post_div_min; |
|
550 | return post_div; |
661 | if (post_div_min < pll->min_post_div) |
551 | } |
662 | post_div_min = pll->min_post_div; |
- | 663 | ||
- | 664 | post_div_max = vco_max / target_clock; |
|
- | 665 | if ((target_clock * post_div_max) > vco_max) |
|
Line 552... | Line 666... | ||
552 | 666 | --post_div_max; |
|
- | 667 | if (post_div_max > pll->max_post_div) |
|
553 | #define MAX_TOLERANCE 10 |
668 | post_div_max = pll->max_post_div; |
554 | 669 | } |
|
555 | void radeon_compute_pll_avivo(struct radeon_pll *pll, |
670 | |
556 | u32 freq, |
671 | /* represent the searched ratio as fractional number */ |
- | 672 | nom = target_clock; |
|
557 | u32 *dot_clock_p, |
673 | den = pll->reference_freq; |
558 | u32 *fb_div_p, |
674 | |
559 | u32 *frac_fb_div_p, |
675 | /* reduce the numbers to a simpler ratio */ |
560 | u32 *ref_div_p, |
676 | avivo_reduce_ratio(&nom, &den, fb_div_min, post_div_min); |
561 | u32 *post_div_p) |
- | |
562 | { |
677 | |
563 | u32 target_clock = freq / 10; |
678 | /* now search for a post divider */ |
564 | u32 post_div = avivo_get_post_div(pll, target_clock); |
679 | if (pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP) |
565 | u32 ref_div = pll->min_ref_div; |
680 | post_div_best = post_div_min; |
- | 681 | else |
|
- | 682 | post_div_best = post_div_max; |
|
566 | u32 fb_div = 0, frac_fb_div = 0, tmp; |
683 | diff_best = ~0; |
567 | 684 | ||
- | 685 | for (post_div = post_div_min; post_div <= post_div_max; ++post_div) { |
|
568 | if (pll->flags & RADEON_PLL_USE_REF_DIV) |
686 | unsigned diff; |
569 | ref_div = pll->reference_div; |
- | |
570 | - | ||
571 | if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) { |
687 | avivo_get_fb_ref_div(nom, den, post_div, fb_div_max, |
572 | avivo_get_fb_div(pll, target_clock, post_div, ref_div, &fb_div, &frac_fb_div); |
688 | ref_div_max, &fb_div, &ref_div); |
573 | frac_fb_div = (100 * frac_fb_div) / pll->reference_freq; |
689 | diff = abs(target_clock - (pll->reference_freq * fb_div) / |
- | 690 | (ref_div * post_div)); |
|
- | 691 | ||
574 | if (frac_fb_div >= 5) { |
692 | if (diff < diff_best || (diff == diff_best && |
575 | frac_fb_div -= 5; |
693 | !(pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP))) { |
576 | frac_fb_div = frac_fb_div / 10; |
694 | |
577 | frac_fb_div++; |
695 | post_div_best = post_div; |
578 | } |
- | |
579 | if (frac_fb_div >= 10) { |
696 | diff_best = diff; |
580 | fb_div++; |
697 | } |
581 | frac_fb_div = 0; |
698 | } |
Line -... | Line 699... | ||
- | 699 | post_div = post_div_best; |
|
582 | } |
700 | |
583 | } else { |
701 | /* get the feedback and reference divider for the optimal value */ |
- | 702 | avivo_get_fb_ref_div(nom, den, post_div, fb_div_max, ref_div_max, |
|
- | 703 | &fb_div, &ref_div); |
|
584 | while (ref_div <= pll->max_ref_div) { |
704 | |
585 | avivo_get_fb_div(pll, target_clock, post_div, ref_div, |
705 | /* reduce the numbers to a simpler ratio once more */ |
- | 706 | /* this also makes sure that the reference divider is large enough */ |
|
- | 707 | avivo_reduce_ratio(&fb_div, &ref_div, fb_div_min, ref_div_min); |
|
- | 708 | ||
- | 709 | /* avoid high jitter with small fractional dividers */ |
|
- | 710 | if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV && (fb_div % 10)) { |
|
586 | &fb_div, &frac_fb_div); |
711 | fb_div_min = max(fb_div_min, (9 - (fb_div % 10)) * 20 + 50); |
587 | if (frac_fb_div >= (pll->reference_freq / 2)) |
712 | if (fb_div < fb_div_min) { |
- | 713 | unsigned tmp = DIV_ROUND_UP(fb_div_min, fb_div); |
|
588 | fb_div++; |
714 | fb_div *= tmp; |
589 | frac_fb_div = 0; |
715 | ref_div *= tmp; |
- | 716 | } |
|
590 | tmp = (pll->reference_freq * fb_div) / (post_div * ref_div); |
717 | } |
Line 591... | Line 718... | ||
591 | tmp = (tmp * 10000) / target_clock; |
718 | |
592 | 719 | /* and finally save the result */ |
|
593 | if (tmp > (10000 + MAX_TOLERANCE)) |
720 | if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) { |
Line 807... | Line 934... | ||
807 | 934 | ||
808 | static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb) |
935 | static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb) |
809 | { |
936 | { |
Line -... | Line 937... | ||
- | 937 | struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb); |
|
- | 938 | ||
- | 939 | if (radeon_fb->obj) { |
|
810 | struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb); |
940 | drm_gem_object_unreference_unlocked(radeon_fb->obj); |
811 | 941 | } |
|
812 | drm_framebuffer_cleanup(fb); |
942 | drm_framebuffer_cleanup(fb); |
Line 813... | Line 943... | ||
813 | kfree(radeon_fb); |
943 | kfree(radeon_fb); |
Line 872... | Line 1002... | ||
872 | { { UNDERSCAN_OFF, "off" }, |
1002 | { { UNDERSCAN_OFF, "off" }, |
873 | { UNDERSCAN_ON, "on" }, |
1003 | { UNDERSCAN_ON, "on" }, |
874 | { UNDERSCAN_AUTO, "auto" }, |
1004 | { UNDERSCAN_AUTO, "auto" }, |
875 | }; |
1005 | }; |
Line -... | Line 1006... | ||
- | 1006 | ||
- | 1007 | static struct drm_prop_enum_list radeon_audio_enum_list[] = |
|
- | 1008 | { { RADEON_AUDIO_DISABLE, "off" }, |
|
- | 1009 | { RADEON_AUDIO_ENABLE, "on" }, |
|
- | 1010 | { RADEON_AUDIO_AUTO, "auto" }, |
|
- | 1011 | }; |
|
- | 1012 | ||
- | 1013 | /* XXX support different dither options? spatial, temporal, both, etc. */ |
|
- | 1014 | static struct drm_prop_enum_list radeon_dither_enum_list[] = |
|
- | 1015 | { { RADEON_FMT_DITHER_DISABLE, "off" }, |
|
- | 1016 | { RADEON_FMT_DITHER_ENABLE, "on" }, |
|
- | 1017 | }; |
|
876 | 1018 | ||
877 | static int radeon_modeset_create_props(struct radeon_device *rdev) |
1019 | static int radeon_modeset_create_props(struct radeon_device *rdev) |
878 | { |
1020 | { |
Line 879... | Line 1021... | ||
879 | int sz; |
1021 | int sz; |
Line 922... | Line 1064... | ||
922 | drm_property_create_range(rdev->ddev, 0, |
1064 | drm_property_create_range(rdev->ddev, 0, |
923 | "underscan vborder", 0, 128); |
1065 | "underscan vborder", 0, 128); |
924 | if (!rdev->mode_info.underscan_vborder_property) |
1066 | if (!rdev->mode_info.underscan_vborder_property) |
925 | return -ENOMEM; |
1067 | return -ENOMEM; |
Line -... | Line 1068... | ||
- | 1068 | ||
- | 1069 | sz = ARRAY_SIZE(radeon_audio_enum_list); |
|
- | 1070 | rdev->mode_info.audio_property = |
|
- | 1071 | drm_property_create_enum(rdev->ddev, 0, |
|
- | 1072 | "audio", |
|
- | 1073 | radeon_audio_enum_list, sz); |
|
- | 1074 | ||
- | 1075 | sz = ARRAY_SIZE(radeon_dither_enum_list); |
|
- | 1076 | rdev->mode_info.dither_property = |
|
- | 1077 | drm_property_create_enum(rdev->ddev, 0, |
|
- | 1078 | "dither", |
|
- | 1079 | radeon_dither_enum_list, sz); |
|
926 | 1080 | ||
927 | return 0; |
1081 | return 0; |
Line 928... | Line 1082... | ||
928 | } |
1082 | } |
929 | 1083 | ||
Line 955... | Line 1109... | ||
955 | int i; |
1109 | int i; |
Line 956... | Line 1110... | ||
956 | 1110 | ||
957 | for (i = 0; i < RADEON_MAX_AFMT_BLOCKS; i++) |
1111 | for (i = 0; i < RADEON_MAX_AFMT_BLOCKS; i++) |
Line 958... | Line 1112... | ||
958 | rdev->mode_info.afmt[i] = NULL; |
1112 | rdev->mode_info.afmt[i] = NULL; |
959 | 1113 | ||
960 | if (ASIC_IS_DCE6(rdev)) { |
1114 | if (ASIC_IS_NODCE(rdev)) { |
- | 1115 | /* nothing to do */ |
|
- | 1116 | } else if (ASIC_IS_DCE4(rdev)) { |
|
- | 1117 | static uint32_t eg_offsets[] = { |
|
- | 1118 | EVERGREEN_CRTC0_REGISTER_OFFSET, |
|
- | 1119 | EVERGREEN_CRTC1_REGISTER_OFFSET, |
|
- | 1120 | EVERGREEN_CRTC2_REGISTER_OFFSET, |
|
- | 1121 | EVERGREEN_CRTC3_REGISTER_OFFSET, |
|
- | 1122 | EVERGREEN_CRTC4_REGISTER_OFFSET, |
|
- | 1123 | EVERGREEN_CRTC5_REGISTER_OFFSET, |
|
- | 1124 | 0x13830 - 0x7030, |
|
- | 1125 | }; |
|
- | 1126 | int num_afmt; |
|
- | 1127 | ||
961 | /* todo */ |
1128 | /* DCE8 has 7 audio blocks tied to DIG encoders */ |
962 | } else if (ASIC_IS_DCE4(rdev)) { |
1129 | /* DCE6 has 6 audio blocks tied to DIG encoders */ |
963 | /* DCE4/5 has 6 audio blocks tied to DIG encoders */ |
- | |
964 | /* DCE4.1 has 2 audio blocks tied to DIG encoders */ |
1130 | /* DCE4/5 has 6 audio blocks tied to DIG encoders */ |
965 | rdev->mode_info.afmt[0] = kzalloc(sizeof(struct radeon_afmt), GFP_KERNEL); |
- | |
966 | if (rdev->mode_info.afmt[0]) { |
1131 | /* DCE4.1 has 2 audio blocks tied to DIG encoders */ |
967 | rdev->mode_info.afmt[0]->offset = EVERGREEN_CRTC0_REGISTER_OFFSET; |
- | |
968 | rdev->mode_info.afmt[0]->id = 0; |
- | |
969 | } |
1132 | if (ASIC_IS_DCE8(rdev)) |
970 | rdev->mode_info.afmt[1] = kzalloc(sizeof(struct radeon_afmt), GFP_KERNEL); |
- | |
971 | if (rdev->mode_info.afmt[1]) { |
1133 | num_afmt = 7; |
972 | rdev->mode_info.afmt[1]->offset = EVERGREEN_CRTC1_REGISTER_OFFSET; |
- | |
973 | rdev->mode_info.afmt[1]->id = 1; |
1134 | else if (ASIC_IS_DCE6(rdev)) |
974 | } |
- | |
975 | if (!ASIC_IS_DCE41(rdev)) { |
1135 | num_afmt = 6; |
976 | rdev->mode_info.afmt[2] = kzalloc(sizeof(struct radeon_afmt), GFP_KERNEL); |
1136 | else if (ASIC_IS_DCE5(rdev)) |
977 | if (rdev->mode_info.afmt[2]) { |
1137 | num_afmt = 6; |
978 | rdev->mode_info.afmt[2]->offset = EVERGREEN_CRTC2_REGISTER_OFFSET; |
- | |
979 | rdev->mode_info.afmt[2]->id = 2; |
- | |
980 | } |
1138 | else if (ASIC_IS_DCE41(rdev)) |
981 | rdev->mode_info.afmt[3] = kzalloc(sizeof(struct radeon_afmt), GFP_KERNEL); |
- | |
982 | if (rdev->mode_info.afmt[3]) { |
1139 | num_afmt = 2; |
983 | rdev->mode_info.afmt[3]->offset = EVERGREEN_CRTC3_REGISTER_OFFSET; |
1140 | else /* DCE4 */ |
984 | rdev->mode_info.afmt[3]->id = 3; |
1141 | num_afmt = 6; |
985 | } |
1142 | |
986 | rdev->mode_info.afmt[4] = kzalloc(sizeof(struct radeon_afmt), GFP_KERNEL); |
- | |
987 | if (rdev->mode_info.afmt[4]) { |
- | |
988 | rdev->mode_info.afmt[4]->offset = EVERGREEN_CRTC4_REGISTER_OFFSET; |
- | |
989 | rdev->mode_info.afmt[4]->id = 4; |
1143 | BUG_ON(num_afmt > ARRAY_SIZE(eg_offsets)); |
990 | } |
1144 | for (i = 0; i < num_afmt; i++) { |
991 | rdev->mode_info.afmt[5] = kzalloc(sizeof(struct radeon_afmt), GFP_KERNEL); |
1145 | rdev->mode_info.afmt[i] = kzalloc(sizeof(struct radeon_afmt), GFP_KERNEL); |
992 | if (rdev->mode_info.afmt[5]) { |
1146 | if (rdev->mode_info.afmt[i]) { |
993 | rdev->mode_info.afmt[5]->offset = EVERGREEN_CRTC5_REGISTER_OFFSET; |
1147 | rdev->mode_info.afmt[i]->offset = eg_offsets[i]; |
994 | rdev->mode_info.afmt[5]->id = 5; |
1148 | rdev->mode_info.afmt[i]->id = i; |
995 | } |
1149 | } |
996 | } |
1150 | } |
997 | } else if (ASIC_IS_DCE3(rdev)) { |
1151 | } else if (ASIC_IS_DCE3(rdev)) { |
Line 1037... | Line 1191... | ||
1037 | int radeon_modeset_init(struct radeon_device *rdev) |
1191 | int radeon_modeset_init(struct radeon_device *rdev) |
1038 | { |
1192 | { |
1039 | int i; |
1193 | int i; |
1040 | int ret; |
1194 | int ret; |
Line -... | Line 1195... | ||
- | 1195 | ||
- | 1196 | ENTER(); |
|
1041 | 1197 | ||
1042 | drm_mode_config_init(rdev->ddev); |
1198 | drm_mode_config_init(rdev->ddev); |
Line 1043... | Line 1199... | ||
1043 | rdev->mode_info.mode_config_initialized = true; |
1199 | rdev->mode_info.mode_config_initialized = true; |
Line 1093... | Line 1249... | ||
1093 | 1249 | ||
1094 | /* initialize hpd */ |
1250 | /* initialize hpd */ |
Line 1095... | Line 1251... | ||
1095 | // radeon_hpd_init(rdev); |
1251 | // radeon_hpd_init(rdev); |
1096 | 1252 | ||
1097 | /* setup afmt */ |
- | |
1098 | // radeon_afmt_init(rdev); |
- | |
1099 | - | ||
Line 1100... | Line 1253... | ||
1100 | /* Initialize power management */ |
1253 | /* setup afmt */ |
- | 1254 | radeon_afmt_init(rdev); |
|
1101 | // radeon_pm_init(rdev); |
1255 | |
Line 1102... | Line 1256... | ||
1102 | 1256 | radeon_fbdev_init(rdev); |
|
1103 | radeon_fbdev_init(rdev); |
1257 | |
Line 1104... | Line 1258... | ||
1104 | // drm_kms_helper_poll_init(rdev->ddev); |
1258 | LEAVE(); |
Line 1179... | Line 1333... | ||
1179 | /* fix up for overscan on hdmi */ |
1333 | /* fix up for overscan on hdmi */ |
1180 | if (ASIC_IS_AVIVO(rdev) && |
1334 | if (ASIC_IS_AVIVO(rdev) && |
1181 | (!(mode->flags & DRM_MODE_FLAG_INTERLACE)) && |
1335 | (!(mode->flags & DRM_MODE_FLAG_INTERLACE)) && |
1182 | ((radeon_encoder->underscan_type == UNDERSCAN_ON) || |
1336 | ((radeon_encoder->underscan_type == UNDERSCAN_ON) || |
1183 | ((radeon_encoder->underscan_type == UNDERSCAN_AUTO) && |
1337 | ((radeon_encoder->underscan_type == UNDERSCAN_AUTO) && |
1184 | drm_detect_hdmi_monitor(radeon_connector->edid) && |
1338 | drm_detect_hdmi_monitor(radeon_connector_edid(connector)) && |
1185 | is_hdtv_mode(mode)))) { |
1339 | is_hdtv_mode(mode)))) { |
1186 | if (radeon_encoder->underscan_hborder != 0) |
1340 | if (radeon_encoder->underscan_hborder != 0) |
1187 | radeon_crtc->h_border = radeon_encoder->underscan_hborder; |
1341 | radeon_crtc->h_border = radeon_encoder->underscan_hborder; |
1188 | else |
1342 | else |
1189 | radeon_crtc->h_border = (mode->hdisplay >> 5) + 16; |
1343 | radeon_crtc->h_border = (mode->hdisplay >> 5) + 16; |
Line 1225... | Line 1379... | ||
1225 | } |
1379 | } |
1226 | return true; |
1380 | return true; |
1227 | } |
1381 | } |
Line 1228... | Line 1382... | ||
1228 | 1382 | ||
1229 | /* |
1383 | /* |
- | 1384 | * Retrieve current video scanout position of crtc on a given gpu, and |
|
1230 | * Retrieve current video scanout position of crtc on a given gpu. |
1385 | * an optional accurate timestamp of when query happened. |
1231 | * |
1386 | * |
1232 | * \param dev Device to query. |
1387 | * \param dev Device to query. |
- | 1388 | * \param crtc Crtc to query. |
|
1233 | * \param crtc Crtc to query. |
1389 | * \param flags Flags from caller (DRM_CALLED_FROM_VBLIRQ or 0). |
1234 | * \param *vpos Location where vertical scanout position should be stored. |
1390 | * \param *vpos Location where vertical scanout position should be stored. |
- | 1391 | * \param *hpos Location where horizontal scanout position should go. |
|
- | 1392 | * \param *stime Target location for timestamp taken immediately before |
|
- | 1393 | * scanout position query. Can be NULL to skip timestamp. |
|
- | 1394 | * \param *etime Target location for timestamp taken immediately after |
|
1235 | * \param *hpos Location where horizontal scanout position should go. |
1395 | * scanout position query. Can be NULL to skip timestamp. |
1236 | * |
1396 | * |
1237 | * Returns vpos as a positive number while in active scanout area. |
1397 | * Returns vpos as a positive number while in active scanout area. |
1238 | * Returns vpos as a negative number inside vblank, counting the number |
1398 | * Returns vpos as a negative number inside vblank, counting the number |
1239 | * of scanlines to go until end of vblank, e.g., -1 means "one scanline |
1399 | * of scanlines to go until end of vblank, e.g., -1 means "one scanline |
Line 1246... | Line 1406... | ||
1246 | * DRM_SCANOUTPOS_ACCURATE = Returned position is accurate. A lack of |
1406 | * DRM_SCANOUTPOS_ACCURATE = Returned position is accurate. A lack of |
1247 | * this flag means that returned position may be offset by a constant but |
1407 | * this flag means that returned position may be offset by a constant but |
1248 | * unknown small number of scanlines wrt. real scanout position. |
1408 | * unknown small number of scanlines wrt. real scanout position. |
1249 | * |
1409 | * |
1250 | */ |
1410 | */ |
1251 | int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, int *vpos, int *hpos) |
1411 | int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int flags, |
- | 1412 | int *vpos, int *hpos, void *stime, void *etime) |
|
1252 | { |
1413 | { |
1253 | u32 stat_crtc = 0, vbl = 0, position = 0; |
1414 | u32 stat_crtc = 0, vbl = 0, position = 0; |
1254 | int vbl_start, vbl_end, vtotal, ret = 0; |
1415 | int vbl_start, vbl_end, vtotal, ret = 0; |
1255 | bool in_vbl = true; |
1416 | bool in_vbl = true; |
Line 1376... | Line 1537... | ||
1376 | 1537 | ||
1377 | /* In vblank? */ |
1538 | /* In vblank? */ |
1378 | if (in_vbl) |
1539 | if (in_vbl) |
Line -... | Line 1540... | ||
- | 1540 | ret |= DRM_SCANOUTPOS_INVBL; |
|
- | 1541 | ||
- | 1542 | /* Is vpos outside nominal vblank area, but less than |
|
- | 1543 | * 1/100 of a frame height away from start of vblank? |
|
- | 1544 | * If so, assume this isn't a massively delayed vblank |
|
- | 1545 | * interrupt, but a vblank interrupt that fired a few |
|
- | 1546 | * microseconds before true start of vblank. Compensate |
|
- | 1547 | * by adding a full frame duration to the final timestamp. |
|
- | 1548 | * Happens, e.g., on ATI R500, R600. |
|
- | 1549 | * |
|
- | 1550 | * We only do this if DRM_CALLED_FROM_VBLIRQ. |
|
- | 1551 | */ |
|
- | 1552 | if ((flags & DRM_CALLED_FROM_VBLIRQ) && !in_vbl) { |
|
- | 1553 | vbl_start = rdev->mode_info.crtcs[crtc]->base.hwmode.crtc_vdisplay; |
|
- | 1554 | vtotal = rdev->mode_info.crtcs[crtc]->base.hwmode.crtc_vtotal; |
|
- | 1555 | ||
- | 1556 | if (vbl_start - *vpos < vtotal / 100) { |
|
- | 1557 | *vpos -= vtotal; |
|
- | 1558 | ||
- | 1559 | /* Signal this correction as "applied". */ |
|
- | 1560 | ret |= 0x8; |
|
- | 1561 | } |
|
1379 | ret |= DRM_SCANOUTPOS_INVBL; |
1562 | } |
1380 | 1563 |