drm/radeon/kms: fix typo in printing the HPD info
[safe/jmp/linux-2.6] / drivers / gpu / drm / radeon / radeon_display.c
index ec3166b..8154cdf 100644 (file)
@@ -68,6 +68,36 @@ static void avivo_crtc_load_lut(struct drm_crtc *crtc)
        WREG32(AVIVO_D1GRPH_LUT_SEL + radeon_crtc->crtc_offset, radeon_crtc->crtc_id);
 }
 
+static void evergreen_crtc_load_lut(struct drm_crtc *crtc)
+{
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+       struct drm_device *dev = crtc->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       int i;
+
+       DRM_DEBUG("%d\n", radeon_crtc->crtc_id);
+       WREG32(EVERGREEN_DC_LUT_CONTROL + radeon_crtc->crtc_offset, 0);
+
+       WREG32(EVERGREEN_DC_LUT_BLACK_OFFSET_BLUE + radeon_crtc->crtc_offset, 0);
+       WREG32(EVERGREEN_DC_LUT_BLACK_OFFSET_GREEN + radeon_crtc->crtc_offset, 0);
+       WREG32(EVERGREEN_DC_LUT_BLACK_OFFSET_RED + radeon_crtc->crtc_offset, 0);
+
+       WREG32(EVERGREEN_DC_LUT_WHITE_OFFSET_BLUE + radeon_crtc->crtc_offset, 0xffff);
+       WREG32(EVERGREEN_DC_LUT_WHITE_OFFSET_GREEN + radeon_crtc->crtc_offset, 0xffff);
+       WREG32(EVERGREEN_DC_LUT_WHITE_OFFSET_RED + radeon_crtc->crtc_offset, 0xffff);
+
+       WREG32(EVERGREEN_DC_LUT_RW_MODE + radeon_crtc->crtc_offset, 0);
+       WREG32(EVERGREEN_DC_LUT_WRITE_EN_MASK + radeon_crtc->crtc_offset, 0x00000007);
+
+       WREG32(EVERGREEN_DC_LUT_RW_INDEX + radeon_crtc->crtc_offset, 0);
+       for (i = 0; i < 256; i++) {
+               WREG32(EVERGREEN_DC_LUT_30_COLOR + radeon_crtc->crtc_offset,
+                      (radeon_crtc->lut_r[i] << 20) |
+                      (radeon_crtc->lut_g[i] << 10) |
+                      (radeon_crtc->lut_b[i] << 0));
+       }
+}
+
 static void legacy_crtc_load_lut(struct drm_crtc *crtc)
 {
        struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
@@ -100,7 +130,9 @@ void radeon_crtc_load_lut(struct drm_crtc *crtc)
        if (!crtc->enabled)
                return;
 
-       if (ASIC_IS_AVIVO(rdev))
+       if (ASIC_IS_DCE4(rdev))
+               evergreen_crtc_load_lut(crtc);
+       else if (ASIC_IS_AVIVO(rdev))
                avivo_crtc_load_lut(crtc);
        else
                legacy_crtc_load_lut(crtc);
@@ -252,8 +284,7 @@ static const char *connector_names[15] = {
        "eDP",
 };
 
-static const char *hpd_names[7] = {
-       "NONE",
+static const char *hpd_names[6] = {
        "HPD1",
        "HPD2",
        "HPD3",
@@ -278,7 +309,7 @@ static void radeon_print_display_setup(struct drm_device *dev)
                DRM_INFO("  %s\n", connector_names[connector->connector_type]);
                if (radeon_connector->hpd.hpd != RADEON_HPD_NONE)
                        DRM_INFO("  %s\n", hpd_names[radeon_connector->hpd.hpd]);
-               if (radeon_connector->ddc_bus)
+               if (radeon_connector->ddc_bus) {
                        DRM_INFO("  DDC: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
                                 radeon_connector->ddc_bus->rec.mask_clk_reg,
                                 radeon_connector->ddc_bus->rec.mask_data_reg,
@@ -288,6 +319,15 @@ static void radeon_print_display_setup(struct drm_device *dev)
                                 radeon_connector->ddc_bus->rec.en_data_reg,
                                 radeon_connector->ddc_bus->rec.y_clk_reg,
                                 radeon_connector->ddc_bus->rec.y_data_reg);
+               } else {
+                       if (connector->connector_type == DRM_MODE_CONNECTOR_VGA ||
+                           connector->connector_type == DRM_MODE_CONNECTOR_DVII ||
+                           connector->connector_type == DRM_MODE_CONNECTOR_DVID ||
+                           connector->connector_type == DRM_MODE_CONNECTOR_DVIA ||
+                           connector->connector_type == DRM_MODE_CONNECTOR_HDMIA ||
+                           connector->connector_type == DRM_MODE_CONNECTOR_HDMIB)
+                               DRM_INFO("  DDC: no ddc bus - possible BIOS bug - please report to xorg-driver-ati@lists.x.org\n");
+               }
                DRM_INFO("  Encoders:\n");
                list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
                        radeon_encoder = to_radeon_encoder(encoder);
@@ -327,10 +367,9 @@ static bool radeon_setup_enc_conn(struct drm_device *dev)
 
        if (rdev->bios) {
                if (rdev->is_atom_bios) {
-                       if (rdev->family >= CHIP_R600)
+                       ret = radeon_get_atom_connector_info_from_supported_devices_table(dev);
+                       if (ret == false)
                                ret = radeon_get_atom_connector_info_from_object_table(dev);
-                       else
-                               ret = radeon_get_atom_connector_info_from_supported_devices_table(dev);
                } else {
                        ret = radeon_get_legacy_connector_info_from_bios(dev);
                        if (ret == false)
@@ -352,6 +391,8 @@ static bool radeon_setup_enc_conn(struct drm_device *dev)
 
 int radeon_ddc_get_modes(struct radeon_connector *radeon_connector)
 {
+       struct drm_device *dev = radeon_connector->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
        int ret = 0;
 
        if ((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) ||
@@ -366,7 +407,9 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector)
        if (!radeon_connector->edid) {
                radeon_connector->edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter);
        }
-
+       /* some servers provide a hardcoded edid in rom for KVMs */
+       if (!radeon_connector->edid)
+               radeon_connector->edid = radeon_combios_get_hardcoded_edid(rdev);
        if (radeon_connector->edid) {
                drm_mode_connector_update_edid_property(&radeon_connector->base, radeon_connector->edid);
                ret = drm_add_edid_modes(&radeon_connector->base, radeon_connector->edid);
@@ -401,13 +444,13 @@ static inline uint32_t radeon_div(uint64_t n, uint32_t d)
        return n;
 }
 
-void radeon_compute_pll(struct radeon_pll *pll,
-                       uint64_t freq,
-                       uint32_t *dot_clock_p,
-                       uint32_t *fb_div_p,
-                       uint32_t *frac_fb_div_p,
-                       uint32_t *ref_div_p,
-                       uint32_t *post_div_p)
+static void radeon_compute_pll_legacy(struct radeon_pll *pll,
+                                     uint64_t freq,
+                                     uint32_t *dot_clock_p,
+                                     uint32_t *fb_div_p,
+                                     uint32_t *frac_fb_div_p,
+                                     uint32_t *ref_div_p,
+                                     uint32_t *post_div_p)
 {
        uint32_t min_ref_div = pll->min_ref_div;
        uint32_t max_ref_div = pll->max_ref_div;
@@ -424,10 +467,19 @@ void radeon_compute_pll(struct radeon_pll *pll,
        uint32_t best_error = 0xffffffff;
        uint32_t best_vco_diff = 1;
        uint32_t post_div;
+       u32 pll_out_min, pll_out_max;
 
        DRM_DEBUG("PLL freq %llu %u %u\n", freq, pll->min_ref_div, pll->max_ref_div);
        freq = freq * 1000;
 
+       if (pll->flags & RADEON_PLL_IS_LCD) {
+               pll_out_min = pll->lcd_pll_out_min;
+               pll_out_max = pll->lcd_pll_out_max;
+       } else {
+               pll_out_min = pll->pll_out_min;
+               pll_out_max = pll->pll_out_max;
+       }
+
        if (pll->flags & RADEON_PLL_USE_REF_DIV)
                min_ref_div = max_ref_div = pll->reference_div;
        else {
@@ -491,10 +543,10 @@ void radeon_compute_pll(struct radeon_pll *pll,
                                tmp = (uint64_t)pll->reference_freq * feedback_div;
                                vco = radeon_div(tmp, ref_div);
 
-                               if (vco < pll->pll_out_min) {
+                               if (vco < pll_out_min) {
                                        min_feed_div = feedback_div + 1;
                                        continue;
-                               } else if (vco > pll->pll_out_max) {
+                               } else if (vco > pll_out_max) {
                                        max_feed_div = feedback_div;
                                        continue;
                                }
@@ -567,110 +619,220 @@ void radeon_compute_pll(struct radeon_pll *pll,
        *post_div_p = best_post_div;
 }
 
-void radeon_compute_pll_avivo(struct radeon_pll *pll,
-                             uint64_t freq,
-                             uint32_t *dot_clock_p,
-                             uint32_t *fb_div_p,
-                             uint32_t *frac_fb_div_p,
-                             uint32_t *ref_div_p,
-                             uint32_t *post_div_p)
+static bool
+calc_fb_div(struct radeon_pll *pll,
+           uint32_t freq,
+            uint32_t post_div,
+            uint32_t ref_div,
+            uint32_t *fb_div,
+            uint32_t *fb_div_frac)
 {
-       fixed20_12 m, n, frac_n, p, f_vco, f_pclk, best_freq;
-       fixed20_12 pll_out_max, pll_out_min;
-       fixed20_12 pll_in_max, pll_in_min;
-       fixed20_12 reference_freq;
-       fixed20_12 error, ffreq, a, b;
-
-       pll_out_max.full = rfixed_const(pll->pll_out_max);
-       pll_out_min.full = rfixed_const(pll->pll_out_min);
-       pll_in_max.full = rfixed_const(pll->pll_in_max);
-       pll_in_min.full = rfixed_const(pll->pll_in_min);
-       reference_freq.full = rfixed_const(pll->reference_freq);
-       do_div(freq, 10);
-       ffreq.full = rfixed_const(freq);
-       error.full = rfixed_const(100 * 100);
+       fixed20_12 feedback_divider, a, b;
+       u32 vco_freq;
 
-       /* max p */
-       p.full = rfixed_div(pll_out_max, ffreq);
-       p.full = rfixed_floor(p);
+       vco_freq = freq * post_div;
+       /* feedback_divider = vco_freq * ref_div / pll->reference_freq; */
+       a.full = dfixed_const(pll->reference_freq);
+       feedback_divider.full = dfixed_const(vco_freq);
+       feedback_divider.full = dfixed_div(feedback_divider, a);
+       a.full = dfixed_const(ref_div);
+       feedback_divider.full = dfixed_mul(feedback_divider, a);
 
-       /* min m */
-       m.full = rfixed_div(reference_freq, pll_in_max);
-       m.full = rfixed_ceil(m);
+       if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) {
+               /* feedback_divider = floor((feedback_divider * 10.0) + 0.5) * 0.1; */
+               a.full = dfixed_const(10);
+               feedback_divider.full = dfixed_mul(feedback_divider, a);
+               feedback_divider.full += dfixed_const_half(0);
+               feedback_divider.full = dfixed_floor(feedback_divider);
+               feedback_divider.full = dfixed_div(feedback_divider, a);
+
+               /* *fb_div = floor(feedback_divider); */
+               a.full = dfixed_floor(feedback_divider);
+               *fb_div = dfixed_trunc(a);
+               /* *fb_div_frac = fmod(feedback_divider, 1.0) * 10.0; */
+               a.full = dfixed_const(10);
+               b.full = dfixed_mul(feedback_divider, a);
+
+               feedback_divider.full = dfixed_floor(feedback_divider);
+               feedback_divider.full = dfixed_mul(feedback_divider, a);
+               feedback_divider.full = b.full - feedback_divider.full;
+               *fb_div_frac = dfixed_trunc(feedback_divider);
+       } else {
+               /* *fb_div = floor(feedback_divider + 0.5); */
+               feedback_divider.full += dfixed_const_half(0);
+               feedback_divider.full = dfixed_floor(feedback_divider);
 
-       while (1) {
-               n.full = rfixed_div(ffreq, reference_freq);
-               n.full = rfixed_mul(n, m);
-               n.full = rfixed_mul(n, p);
+               *fb_div = dfixed_trunc(feedback_divider);
+               *fb_div_frac = 0;
+       }
 
-               f_vco.full = rfixed_div(n, m);
-               f_vco.full = rfixed_mul(f_vco, reference_freq);
+       if (((*fb_div) < pll->min_feedback_div) || ((*fb_div) > pll->max_feedback_div))
+               return false;
+       else
+               return true;
+}
 
-               f_pclk.full = rfixed_div(f_vco, p);
+static bool
+calc_fb_ref_div(struct radeon_pll *pll,
+               uint32_t freq,
+               uint32_t post_div,
+               uint32_t *fb_div,
+                uint32_t *fb_div_frac,
+                uint32_t *ref_div)
+{
+       fixed20_12 ffreq, max_error, error, pll_out, a;
+       u32 vco;
+       u32 pll_out_min, pll_out_max;
 
-               if (f_pclk.full > ffreq.full)
-                       error.full = f_pclk.full - ffreq.full;
-               else
-                       error.full = ffreq.full - f_pclk.full;
-               error.full = rfixed_div(error, f_pclk);
-               a.full = rfixed_const(100 * 100);
-               error.full = rfixed_mul(error, a);
-
-               a.full = rfixed_mul(m, p);
-               a.full = rfixed_div(n, a);
-               best_freq.full = rfixed_mul(reference_freq, a);
-
-               if (rfixed_trunc(error) < 25)
-                       break;
-
-               a.full = rfixed_const(1);
-               m.full = m.full + a.full;
-               a.full = rfixed_div(reference_freq, m);
-               if (a.full >= pll_in_min.full)
-                       continue;
+       if (pll->flags & RADEON_PLL_IS_LCD) {
+               pll_out_min = pll->lcd_pll_out_min;
+               pll_out_max = pll->lcd_pll_out_max;
+       } else {
+               pll_out_min = pll->pll_out_min;
+               pll_out_max = pll->pll_out_max;
+       }
 
-               m.full = rfixed_div(reference_freq, pll_in_max);
-               m.full = rfixed_ceil(m);
-               a.full= rfixed_const(1);
-               p.full = p.full - a.full;
-               a.full = rfixed_mul(p, ffreq);
-               if (a.full >= pll_out_min.full)
-                       continue;
-               else {
-                       DRM_ERROR("Unable to find pll dividers\n");
-                       break;
+       ffreq.full = dfixed_const(freq);
+       /* max_error = ffreq * 0.0025; */
+       a.full = dfixed_const(400);
+       max_error.full = dfixed_div(ffreq, a);
+
+       for ((*ref_div) = pll->min_ref_div; (*ref_div) < pll->max_ref_div; ++(*ref_div)) {
+               if (calc_fb_div(pll, freq, post_div, (*ref_div), fb_div, fb_div_frac)) {
+                       vco = pll->reference_freq * (((*fb_div) * 10) + (*fb_div_frac));
+                       vco = vco / ((*ref_div) * 10);
+
+                       if ((vco < pll_out_min) || (vco > pll_out_max))
+                               continue;
+
+                       /* pll_out = vco / post_div; */
+                       a.full = dfixed_const(post_div);
+                       pll_out.full = dfixed_const(vco);
+                       pll_out.full = dfixed_div(pll_out, a);
+
+                       if (pll_out.full >= ffreq.full) {
+                               error.full = pll_out.full - ffreq.full;
+                               if (error.full <= max_error.full)
+                                       return true;
+                       }
+               }
+       }
+       return false;
+}
+
+static void radeon_compute_pll_new(struct radeon_pll *pll,
+                                  uint64_t freq,
+                                  uint32_t *dot_clock_p,
+                                  uint32_t *fb_div_p,
+                                  uint32_t *frac_fb_div_p,
+                                  uint32_t *ref_div_p,
+                                  uint32_t *post_div_p)
+{
+       u32 fb_div = 0, fb_div_frac = 0, post_div = 0, ref_div = 0;
+       u32 best_freq = 0, vco_frequency;
+       u32 pll_out_min, pll_out_max;
+
+       if (pll->flags & RADEON_PLL_IS_LCD) {
+               pll_out_min = pll->lcd_pll_out_min;
+               pll_out_max = pll->lcd_pll_out_max;
+       } else {
+               pll_out_min = pll->pll_out_min;
+               pll_out_max = pll->pll_out_max;
+       }
+
+       /* freq = freq / 10; */
+       do_div(freq, 10);
+
+       if (pll->flags & RADEON_PLL_USE_POST_DIV) {
+               post_div = pll->post_div;
+               if ((post_div < pll->min_post_div) || (post_div > pll->max_post_div))
+                       goto done;
+
+               vco_frequency = freq * post_div;
+               if ((vco_frequency < pll_out_min) || (vco_frequency > pll_out_max))
+                       goto done;
+
+               if (pll->flags & RADEON_PLL_USE_REF_DIV) {
+                       ref_div = pll->reference_div;
+                       if ((ref_div < pll->min_ref_div) || (ref_div > pll->max_ref_div))
+                               goto done;
+                       if (!calc_fb_div(pll, freq, post_div, ref_div, &fb_div, &fb_div_frac))
+                               goto done;
+               }
+       } else {
+               for (post_div = pll->max_post_div; post_div >= pll->min_post_div; --post_div) {
+                       if (pll->flags & RADEON_PLL_LEGACY) {
+                               if ((post_div == 5) ||
+                                   (post_div == 7) ||
+                                   (post_div == 9) ||
+                                   (post_div == 10) ||
+                                   (post_div == 11))
+                                       continue;
+                       }
+
+                       if ((pll->flags & RADEON_PLL_NO_ODD_POST_DIV) && (post_div & 1))
+                               continue;
+
+                       vco_frequency = freq * post_div;
+                       if ((vco_frequency < pll_out_min) || (vco_frequency > pll_out_max))
+                               continue;
+                       if (pll->flags & RADEON_PLL_USE_REF_DIV) {
+                               ref_div = pll->reference_div;
+                               if ((ref_div < pll->min_ref_div) || (ref_div > pll->max_ref_div))
+                                       goto done;
+                               if (calc_fb_div(pll, freq, post_div, ref_div, &fb_div, &fb_div_frac))
+                                       break;
+                       } else {
+                               if (calc_fb_ref_div(pll, freq, post_div, &fb_div, &fb_div_frac, &ref_div))
+                                       break;
+                       }
                }
        }
 
-       a.full = rfixed_const(10);
-       b.full = rfixed_mul(n, a);
+       best_freq = pll->reference_freq * 10 * fb_div;
+       best_freq += pll->reference_freq * fb_div_frac;
+       best_freq = best_freq / (ref_div * post_div);
 
-       frac_n.full = rfixed_floor(n);
-       frac_n.full = rfixed_mul(frac_n, a);
-       frac_n.full = b.full - frac_n.full;
+done:
+       if (best_freq == 0)
+               DRM_ERROR("Couldn't find valid PLL dividers\n");
 
-       *dot_clock_p = rfixed_trunc(best_freq);
-       *fb_div_p = rfixed_trunc(n);
-       *frac_fb_div_p = rfixed_trunc(frac_n);
-       *ref_div_p = rfixed_trunc(m);
-       *post_div_p = rfixed_trunc(p);
+       *dot_clock_p = best_freq / 10;
+       *fb_div_p = fb_div;
+       *frac_fb_div_p = fb_div_frac;
+       *ref_div_p = ref_div;
+       *post_div_p = post_div;
 
-       DRM_DEBUG("%u %d.%d, %d, %d\n", *dot_clock_p * 10, *fb_div_p, *frac_fb_div_p, *ref_div_p, *post_div_p);
+       DRM_DEBUG("%u %d.%d, %d, %d\n", *dot_clock_p, *fb_div_p, *frac_fb_div_p, *ref_div_p, *post_div_p);
+}
+
+void radeon_compute_pll(struct radeon_pll *pll,
+                       uint64_t freq,
+                       uint32_t *dot_clock_p,
+                       uint32_t *fb_div_p,
+                       uint32_t *frac_fb_div_p,
+                       uint32_t *ref_div_p,
+                       uint32_t *post_div_p)
+{
+       switch (pll->algo) {
+       case PLL_ALGO_NEW:
+               radeon_compute_pll_new(pll, freq, dot_clock_p, fb_div_p,
+                                      frac_fb_div_p, ref_div_p, post_div_p);
+               break;
+       case PLL_ALGO_LEGACY:
+       default:
+               radeon_compute_pll_legacy(pll, freq, dot_clock_p, fb_div_p,
+                                         frac_fb_div_p, ref_div_p, post_div_p);
+               break;
+       }
 }
 
 static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb)
 {
        struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb);
-       struct drm_device *dev = fb->dev;
 
-       if (fb->fbdev)
-               radeonfb_remove(dev, fb);
-
-       if (radeon_fb->obj) {
-               mutex_lock(&dev->struct_mutex);
-               drm_gem_object_unreference(radeon_fb->obj);
-               mutex_unlock(&dev->struct_mutex);
-       }
+       if (radeon_fb->obj)
+               drm_gem_object_unreference_unlocked(radeon_fb->obj);
        drm_framebuffer_cleanup(fb);
        kfree(radeon_fb);
 }
@@ -689,21 +851,15 @@ static const struct drm_framebuffer_funcs radeon_fb_funcs = {
        .create_handle = radeon_user_framebuffer_create_handle,
 };
 
-struct drm_framebuffer *
-radeon_framebuffer_create(struct drm_device *dev,
-                         struct drm_mode_fb_cmd *mode_cmd,
-                         struct drm_gem_object *obj)
+void
+radeon_framebuffer_init(struct drm_device *dev,
+                       struct radeon_framebuffer *rfb,
+                       struct drm_mode_fb_cmd *mode_cmd,
+                       struct drm_gem_object *obj)
 {
-       struct radeon_framebuffer *radeon_fb;
-
-       radeon_fb = kzalloc(sizeof(*radeon_fb), GFP_KERNEL);
-       if (radeon_fb == NULL) {
-               return NULL;
-       }
-       drm_framebuffer_init(dev, &radeon_fb->base, &radeon_fb_funcs);
-       drm_helper_mode_fill_fb_struct(&radeon_fb->base, mode_cmd);
-       radeon_fb->obj = obj;
-       return &radeon_fb->base;
+       rfb->obj = obj;
+       drm_framebuffer_init(dev, &rfb->base, &radeon_fb_funcs);
+       drm_helper_mode_fill_fb_struct(&rfb->base, mode_cmd);
 }
 
 static struct drm_framebuffer *
@@ -712,6 +868,7 @@ radeon_user_framebuffer_create(struct drm_device *dev,
                               struct drm_mode_fb_cmd *mode_cmd)
 {
        struct drm_gem_object *obj;
+       struct radeon_framebuffer *radeon_fb;
 
        obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle);
        if (obj ==  NULL) {
@@ -719,12 +876,26 @@ radeon_user_framebuffer_create(struct drm_device *dev,
                        "can't create framebuffer\n", mode_cmd->handle);
                return NULL;
        }
-       return radeon_framebuffer_create(dev, mode_cmd, obj);
+
+       radeon_fb = kzalloc(sizeof(*radeon_fb), GFP_KERNEL);
+       if (radeon_fb == NULL) {
+               return NULL;
+       }
+
+       radeon_framebuffer_init(dev, radeon_fb, mode_cmd, obj);
+
+       return &radeon_fb->base;
+}
+
+static void radeon_output_poll_changed(struct drm_device *dev)
+{
+       struct radeon_device *rdev = dev->dev_private;
+       radeon_fb_output_poll_changed(rdev);
 }
 
 static const struct drm_mode_config_funcs radeon_mode_funcs = {
        .fb_create = radeon_user_framebuffer_create,
-       .fb_changed = radeonfb_probe,
+       .output_poll_changed = radeon_output_poll_changed
 };
 
 struct drm_prop_enum_list {
@@ -804,9 +975,29 @@ static int radeon_modeset_create_props(struct radeon_device *rdev)
        return 0;
 }
 
+void radeon_update_display_priority(struct radeon_device *rdev)
+{
+       /* adjustment options for the display watermarks */
+       if ((radeon_disp_priority == 0) || (radeon_disp_priority > 2)) {
+               /* set display priority to high for r3xx, rv515 chips
+                * this avoids flickering due to underflow to the
+                * display controllers during heavy acceleration.
+                * Don't force high on rs4xx igp chips as it seems to
+                * affect the sound card.  See kernel bug 15982.
+                */
+               if ((ASIC_IS_R300(rdev) || (rdev->family == CHIP_RV515)) &&
+                   !(rdev->flags & RADEON_IS_IGP))
+                       rdev->disp_priority = 2;
+               else
+                       rdev->disp_priority = 0;
+       } else
+               rdev->disp_priority = radeon_disp_priority;
+
+}
+
 int radeon_modeset_init(struct radeon_device *rdev)
 {
-       int num_crtc = 2, i;
+       int i;
        int ret;
 
        drm_mode_config_init(rdev->ddev);
@@ -829,11 +1020,14 @@ int radeon_modeset_init(struct radeon_device *rdev)
                return ret;
        }
 
-       if (rdev->flags & RADEON_SINGLE_CRTC)
-               num_crtc = 1;
+       /* check combios for a valid hardcoded EDID - Sun servers */
+       if (!rdev->is_atom_bios) {
+               /* check for hardcoded EDID in BIOS */
+               radeon_combios_check_hardcoded_edid(rdev);
+       }
 
        /* allocate crtcs */
-       for (i = 0; i < num_crtc; i++) {
+       for (i = 0; i < rdev->num_crtc; i++) {
                radeon_crtc_init(rdev->ddev, i);
        }
 
@@ -844,13 +1038,24 @@ int radeon_modeset_init(struct radeon_device *rdev)
        }
        /* initialize hpd */
        radeon_hpd_init(rdev);
-       drm_helper_initial_config(rdev->ddev);
+
+       /* Initialize power management */
+       radeon_pm_init(rdev);
+
+       radeon_fbdev_init(rdev);
+       drm_kms_helper_poll_init(rdev->ddev);
+
        return 0;
 }
 
 void radeon_modeset_fini(struct radeon_device *rdev)
 {
+       radeon_fbdev_fini(rdev);
+       kfree(rdev->mode_info.bios_hardcoded_edid);
+       radeon_pm_fini(rdev);
+
        if (rdev->mode_info.mode_config_initialized) {
+               drm_kms_helper_poll_fini(rdev->ddev);
                radeon_hpd_fini(rdev);
                drm_mode_config_cleanup(rdev->ddev);
                rdev->mode_info.mode_config_initialized = false;
@@ -900,15 +1105,15 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
        }
        if (radeon_crtc->rmx_type != RMX_OFF) {
                fixed20_12 a, b;
-               a.full = rfixed_const(crtc->mode.vdisplay);
-               b.full = rfixed_const(radeon_crtc->native_mode.hdisplay);
-               radeon_crtc->vsc.full = rfixed_div(a, b);
-               a.full = rfixed_const(crtc->mode.hdisplay);
-               b.full = rfixed_const(radeon_crtc->native_mode.vdisplay);
-               radeon_crtc->hsc.full = rfixed_div(a, b);
+               a.full = dfixed_const(crtc->mode.vdisplay);
+               b.full = dfixed_const(radeon_crtc->native_mode.hdisplay);
+               radeon_crtc->vsc.full = dfixed_div(a, b);
+               a.full = dfixed_const(crtc->mode.hdisplay);
+               b.full = dfixed_const(radeon_crtc->native_mode.vdisplay);
+               radeon_crtc->hsc.full = dfixed_div(a, b);
        } else {
-               radeon_crtc->vsc.full = rfixed_const(1);
-               radeon_crtc->hsc.full = rfixed_const(1);
+               radeon_crtc->vsc.full = dfixed_const(1);
+               radeon_crtc->hsc.full = dfixed_const(1);
        }
        return true;
 }