summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/radeon/radeon_display.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_display.c')
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c196
1 files changed, 165 insertions, 31 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index c85df4afcb7a..6a92f994cc26 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -234,7 +234,7 @@ static const char *encoder_names[34] = {
"INTERNAL_UNIPHY2",
};
-static const char *connector_names[13] = {
+static const char *connector_names[15] = {
"Unknown",
"VGA",
"DVI-I",
@@ -248,6 +248,18 @@ static const char *connector_names[13] = {
"DisplayPort",
"HDMI-A",
"HDMI-B",
+ "TV",
+ "eDP",
+};
+
+static const char *hpd_names[7] = {
+ "NONE",
+ "HPD1",
+ "HPD2",
+ "HPD3",
+ "HPD4",
+ "HPD5",
+ "HPD6",
};
static void radeon_print_display_setup(struct drm_device *dev)
@@ -264,16 +276,18 @@ static void radeon_print_display_setup(struct drm_device *dev)
radeon_connector = to_radeon_connector(connector);
DRM_INFO("Connector %d:\n", i);
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)
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,
radeon_connector->ddc_bus->rec.a_clk_reg,
radeon_connector->ddc_bus->rec.a_data_reg,
- radeon_connector->ddc_bus->rec.put_clk_reg,
- radeon_connector->ddc_bus->rec.put_data_reg,
- radeon_connector->ddc_bus->rec.get_clk_reg,
- radeon_connector->ddc_bus->rec.get_data_reg);
+ radeon_connector->ddc_bus->rec.en_clk_reg,
+ radeon_connector->ddc_bus->rec.en_data_reg,
+ radeon_connector->ddc_bus->rec.y_clk_reg,
+ radeon_connector->ddc_bus->rec.y_data_reg);
DRM_INFO(" Encoders:\n");
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
radeon_encoder = to_radeon_encoder(encoder);
@@ -317,13 +331,17 @@ static bool radeon_setup_enc_conn(struct drm_device *dev)
ret = radeon_get_atom_connector_info_from_object_table(dev);
else
ret = radeon_get_atom_connector_info_from_supported_devices_table(dev);
- } else
+ } else {
ret = radeon_get_legacy_connector_info_from_bios(dev);
+ if (ret == false)
+ ret = radeon_get_legacy_connector_info_from_table(dev);
+ }
} else {
if (!ASIC_IS_AVIVO(rdev))
ret = radeon_get_legacy_connector_info_from_table(dev);
}
if (ret) {
+ radeon_setup_encoder_clones(dev);
radeon_print_display_setup(dev);
list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head)
radeon_ddc_dump(drm_connector);
@@ -336,12 +354,19 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector)
{
int ret = 0;
+ if ((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) ||
+ (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP)) {
+ struct radeon_connector_atom_dig *dig = radeon_connector->con_priv;
+ if ((dig->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT ||
+ dig->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) && dig->dp_i2c_bus)
+ radeon_connector->edid = drm_get_edid(&radeon_connector->base, &dig->dp_i2c_bus->adapter);
+ }
if (!radeon_connector->ddc_bus)
return -1;
if (!radeon_connector->edid) {
- radeon_i2c_do_lock(radeon_connector, 1);
+ radeon_i2c_do_lock(radeon_connector->ddc_bus, 1);
radeon_connector->edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter);
- radeon_i2c_do_lock(radeon_connector, 0);
+ radeon_i2c_do_lock(radeon_connector->ddc_bus, 0);
}
if (radeon_connector->edid) {
@@ -361,9 +386,9 @@ static int radeon_ddc_dump(struct drm_connector *connector)
if (!radeon_connector->ddc_bus)
return -1;
- radeon_i2c_do_lock(radeon_connector, 1);
+ radeon_i2c_do_lock(radeon_connector->ddc_bus, 1);
edid = drm_get_edid(connector, &radeon_connector->ddc_bus->adapter);
- radeon_i2c_do_lock(radeon_connector, 0);
+ radeon_i2c_do_lock(radeon_connector->ddc_bus, 0);
if (edid) {
kfree(edid);
}
@@ -386,11 +411,12 @@ void radeon_compute_pll(struct radeon_pll *pll,
uint32_t *fb_div_p,
uint32_t *frac_fb_div_p,
uint32_t *ref_div_p,
- uint32_t *post_div_p,
- int flags)
+ uint32_t *post_div_p)
{
uint32_t min_ref_div = pll->min_ref_div;
uint32_t max_ref_div = pll->max_ref_div;
+ uint32_t min_post_div = pll->min_post_div;
+ uint32_t max_post_div = pll->max_post_div;
uint32_t min_fractional_feed_div = 0;
uint32_t max_fractional_feed_div = 0;
uint32_t best_vco = pll->best_vco;
@@ -406,7 +432,7 @@ void radeon_compute_pll(struct radeon_pll *pll,
DRM_DEBUG("PLL freq %llu %u %u\n", freq, pll->min_ref_div, pll->max_ref_div);
freq = freq * 1000;
- if (flags & RADEON_PLL_USE_REF_DIV)
+ if (pll->flags & RADEON_PLL_USE_REF_DIV)
min_ref_div = max_ref_div = pll->reference_div;
else {
while (min_ref_div < max_ref_div-1) {
@@ -421,19 +447,22 @@ void radeon_compute_pll(struct radeon_pll *pll,
}
}
- if (flags & RADEON_PLL_USE_FRAC_FB_DIV) {
+ if (pll->flags & RADEON_PLL_USE_POST_DIV)
+ min_post_div = max_post_div = pll->post_div;
+
+ if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) {
min_fractional_feed_div = pll->min_frac_feedback_div;
max_fractional_feed_div = pll->max_frac_feedback_div;
}
- for (post_div = pll->min_post_div; post_div <= pll->max_post_div; ++post_div) {
+ for (post_div = min_post_div; post_div <= max_post_div; ++post_div) {
uint32_t ref_div;
- if ((flags & RADEON_PLL_NO_ODD_POST_DIV) && (post_div & 1))
+ if ((pll->flags & RADEON_PLL_NO_ODD_POST_DIV) && (post_div & 1))
continue;
/* legacy radeons only have a few post_divs */
- if (flags & RADEON_PLL_LEGACY) {
+ if (pll->flags & RADEON_PLL_LEGACY) {
if ((post_div == 5) ||
(post_div == 7) ||
(post_div == 9) ||
@@ -480,7 +509,7 @@ void radeon_compute_pll(struct radeon_pll *pll,
tmp += (uint64_t)pll->reference_freq * 1000 * frac_feedback_div;
current_freq = radeon_div(tmp, ref_div * post_div);
- if (flags & RADEON_PLL_PREFER_CLOSEST_LOWER) {
+ if (pll->flags & RADEON_PLL_PREFER_CLOSEST_LOWER) {
error = freq - current_freq;
error = error < 0 ? 0xffffffff : error;
} else
@@ -507,12 +536,12 @@ void radeon_compute_pll(struct radeon_pll *pll,
best_freq = current_freq;
best_error = error;
best_vco_diff = vco_diff;
- } else if (((flags & RADEON_PLL_PREFER_LOW_REF_DIV) && (ref_div < best_ref_div)) ||
- ((flags & RADEON_PLL_PREFER_HIGH_REF_DIV) && (ref_div > best_ref_div)) ||
- ((flags & RADEON_PLL_PREFER_LOW_FB_DIV) && (feedback_div < best_feedback_div)) ||
- ((flags & RADEON_PLL_PREFER_HIGH_FB_DIV) && (feedback_div > best_feedback_div)) ||
- ((flags & RADEON_PLL_PREFER_LOW_POST_DIV) && (post_div < best_post_div)) ||
- ((flags & RADEON_PLL_PREFER_HIGH_POST_DIV) && (post_div > best_post_div))) {
+ } else if (((pll->flags & RADEON_PLL_PREFER_LOW_REF_DIV) && (ref_div < best_ref_div)) ||
+ ((pll->flags & RADEON_PLL_PREFER_HIGH_REF_DIV) && (ref_div > best_ref_div)) ||
+ ((pll->flags & RADEON_PLL_PREFER_LOW_FB_DIV) && (feedback_div < best_feedback_div)) ||
+ ((pll->flags & RADEON_PLL_PREFER_HIGH_FB_DIV) && (feedback_div > best_feedback_div)) ||
+ ((pll->flags & RADEON_PLL_PREFER_LOW_POST_DIV) && (post_div < best_post_div)) ||
+ ((pll->flags & RADEON_PLL_PREFER_HIGH_POST_DIV) && (post_div > best_post_div))) {
best_post_div = post_div;
best_ref_div = ref_div;
best_feedback_div = feedback_div;
@@ -542,6 +571,97 @@ 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)
+{
+ 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);
+
+ /* max p */
+ p.full = rfixed_div(pll_out_max, ffreq);
+ p.full = rfixed_floor(p);
+
+ /* min m */
+ m.full = rfixed_div(reference_freq, pll_in_max);
+ m.full = rfixed_ceil(m);
+
+ while (1) {
+ n.full = rfixed_div(ffreq, reference_freq);
+ n.full = rfixed_mul(n, m);
+ n.full = rfixed_mul(n, p);
+
+ f_vco.full = rfixed_div(n, m);
+ f_vco.full = rfixed_mul(f_vco, reference_freq);
+
+ f_pclk.full = rfixed_div(f_vco, p);
+
+ 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;
+
+ 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;
+ }
+ }
+
+ a.full = rfixed_const(10);
+ b.full = rfixed_mul(n, a);
+
+ frac_n.full = rfixed_floor(n);
+ frac_n.full = rfixed_mul(frac_n, a);
+ frac_n.full = b.full - frac_n.full;
+
+ *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);
+
+ 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);
+}
+
static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb)
{
struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb);
@@ -551,7 +671,6 @@ static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb)
radeonfb_remove(dev, fb);
if (radeon_fb->obj) {
- radeon_gem_object_unpin(radeon_fb->obj);
mutex_lock(&dev->struct_mutex);
drm_gem_object_unreference(radeon_fb->obj);
mutex_unlock(&dev->struct_mutex);
@@ -599,7 +718,11 @@ radeon_user_framebuffer_create(struct drm_device *dev,
struct drm_gem_object *obj;
obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle);
-
+ if (obj == NULL) {
+ dev_err(&dev->pdev->dev, "No GEM object associated to handle 0x%08X, "
+ "can't create framebuffer\n", mode_cmd->handle);
+ return NULL;
+ }
return radeon_framebuffer_create(dev, mode_cmd, obj);
}
@@ -629,7 +752,7 @@ static struct drm_prop_enum_list radeon_tv_std_enum_list[] =
{ TV_STD_SECAM, "secam" },
};
-int radeon_modeset_create_props(struct radeon_device *rdev)
+static int radeon_modeset_create_props(struct radeon_device *rdev)
{
int i, sz;
@@ -642,7 +765,7 @@ int radeon_modeset_create_props(struct radeon_device *rdev)
return -ENOMEM;
rdev->mode_info.coherent_mode_property->values[0] = 0;
- rdev->mode_info.coherent_mode_property->values[0] = 1;
+ rdev->mode_info.coherent_mode_property->values[1] = 1;
}
if (!ASIC_IS_AVIVO(rdev)) {
@@ -666,7 +789,7 @@ int radeon_modeset_create_props(struct radeon_device *rdev)
if (!rdev->mode_info.load_detect_property)
return -ENOMEM;
rdev->mode_info.load_detect_property->values[0] = 0;
- rdev->mode_info.load_detect_property->values[0] = 1;
+ rdev->mode_info.load_detect_property->values[1] = 1;
drm_mode_create_scaling_mode_property(rdev->ddev);
@@ -723,6 +846,8 @@ int radeon_modeset_init(struct radeon_device *rdev)
if (!ret) {
return ret;
}
+ /* initialize hpd */
+ radeon_hpd_init(rdev);
drm_helper_initial_config(rdev->ddev);
return 0;
}
@@ -730,6 +855,7 @@ int radeon_modeset_init(struct radeon_device *rdev)
void radeon_modeset_fini(struct radeon_device *rdev)
{
if (rdev->mode_info.mode_config_initialized) {
+ radeon_hpd_fini(rdev);
drm_mode_config_cleanup(rdev->ddev);
rdev->mode_info.mode_config_initialized = false;
}
@@ -750,9 +876,17 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
if (encoder->crtc != crtc)
continue;
if (first) {
- radeon_crtc->rmx_type = radeon_encoder->rmx_type;
+ /* set scaling */
+ if (radeon_encoder->rmx_type == RMX_OFF)
+ radeon_crtc->rmx_type = RMX_OFF;
+ else if (mode->hdisplay < radeon_encoder->native_mode.hdisplay ||
+ mode->vdisplay < radeon_encoder->native_mode.vdisplay)
+ radeon_crtc->rmx_type = radeon_encoder->rmx_type;
+ else
+ radeon_crtc->rmx_type = RMX_OFF;
+ /* copy native mode */
memcpy(&radeon_crtc->native_mode,
- &radeon_encoder->native_mode,
+ &radeon_encoder->native_mode,
sizeof(struct drm_display_mode));
first = false;
} else {