drm/radeon/kms: enable underscan option for digital connectors
This connector attribute allows you to enable or disable underscan on a digital output to compensate for panels that automatically overscan (e.g., many HDMI TVs). Valid values for the attribute are: off - forces underscan off on - forces underscan on auto - enables underscan if an HDMI TV is connected, off otherwise default value is auto. Signed-off-by: Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
This commit is contained in:
parent
d65d65b175
commit
5b1714d386
@ -44,10 +44,6 @@ static void atombios_overscan_setup(struct drm_crtc *crtc,
|
||||
|
||||
memset(&args, 0, sizeof(args));
|
||||
|
||||
args.usOverscanRight = 0;
|
||||
args.usOverscanLeft = 0;
|
||||
args.usOverscanBottom = 0;
|
||||
args.usOverscanTop = 0;
|
||||
args.ucCRTC = radeon_crtc->crtc_id;
|
||||
|
||||
switch (radeon_crtc->rmx_type) {
|
||||
@ -56,7 +52,6 @@ static void atombios_overscan_setup(struct drm_crtc *crtc,
|
||||
args.usOverscanBottom = (adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2;
|
||||
args.usOverscanLeft = (adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2;
|
||||
args.usOverscanRight = (adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2;
|
||||
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
|
||||
break;
|
||||
case RMX_ASPECT:
|
||||
a1 = mode->crtc_vdisplay * adjusted_mode->crtc_hdisplay;
|
||||
@ -69,17 +64,16 @@ static void atombios_overscan_setup(struct drm_crtc *crtc,
|
||||
args.usOverscanLeft = (adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2;
|
||||
args.usOverscanRight = (adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2;
|
||||
}
|
||||
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
|
||||
break;
|
||||
case RMX_FULL:
|
||||
default:
|
||||
args.usOverscanRight = 0;
|
||||
args.usOverscanLeft = 0;
|
||||
args.usOverscanBottom = 0;
|
||||
args.usOverscanTop = 0;
|
||||
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
|
||||
args.usOverscanRight = radeon_crtc->h_border;
|
||||
args.usOverscanLeft = radeon_crtc->h_border;
|
||||
args.usOverscanBottom = radeon_crtc->v_border;
|
||||
args.usOverscanTop = radeon_crtc->v_border;
|
||||
break;
|
||||
}
|
||||
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
|
||||
}
|
||||
|
||||
static void atombios_scaler_setup(struct drm_crtc *crtc)
|
||||
@ -282,22 +276,22 @@ atombios_set_crtc_dtd_timing(struct drm_crtc *crtc,
|
||||
u16 misc = 0;
|
||||
|
||||
memset(&args, 0, sizeof(args));
|
||||
args.usH_Size = cpu_to_le16(mode->crtc_hdisplay);
|
||||
args.usH_Size = cpu_to_le16(mode->crtc_hdisplay - (radeon_crtc->h_border * 2));
|
||||
args.usH_Blanking_Time =
|
||||
cpu_to_le16(mode->crtc_hblank_end - mode->crtc_hdisplay);
|
||||
args.usV_Size = cpu_to_le16(mode->crtc_vdisplay);
|
||||
cpu_to_le16(mode->crtc_hblank_end - mode->crtc_hdisplay + (radeon_crtc->h_border * 2));
|
||||
args.usV_Size = cpu_to_le16(mode->crtc_vdisplay - (radeon_crtc->v_border * 2));
|
||||
args.usV_Blanking_Time =
|
||||
cpu_to_le16(mode->crtc_vblank_end - mode->crtc_vdisplay);
|
||||
cpu_to_le16(mode->crtc_vblank_end - mode->crtc_vdisplay + (radeon_crtc->v_border * 2));
|
||||
args.usH_SyncOffset =
|
||||
cpu_to_le16(mode->crtc_hsync_start - mode->crtc_hdisplay);
|
||||
cpu_to_le16(mode->crtc_hsync_start - mode->crtc_hdisplay + radeon_crtc->h_border);
|
||||
args.usH_SyncWidth =
|
||||
cpu_to_le16(mode->crtc_hsync_end - mode->crtc_hsync_start);
|
||||
args.usV_SyncOffset =
|
||||
cpu_to_le16(mode->crtc_vsync_start - mode->crtc_vdisplay);
|
||||
cpu_to_le16(mode->crtc_vsync_start - mode->crtc_vdisplay + radeon_crtc->v_border);
|
||||
args.usV_SyncWidth =
|
||||
cpu_to_le16(mode->crtc_vsync_end - mode->crtc_vsync_start);
|
||||
/*args.ucH_Border = mode->hborder;*/
|
||||
/*args.ucV_Border = mode->vborder;*/
|
||||
args.ucH_Border = radeon_crtc->h_border;
|
||||
args.ucV_Border = radeon_crtc->v_border;
|
||||
|
||||
if (mode->flags & DRM_MODE_FLAG_NVSYNC)
|
||||
misc |= ATOM_VSYNC_POLARITY;
|
||||
@ -1176,10 +1170,8 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc,
|
||||
atombios_crtc_set_pll(crtc, adjusted_mode);
|
||||
atombios_enable_ss(crtc);
|
||||
|
||||
if (ASIC_IS_DCE4(rdev))
|
||||
if (ASIC_IS_AVIVO(rdev))
|
||||
atombios_set_crtc_dtd_timing(crtc, adjusted_mode);
|
||||
else if (ASIC_IS_AVIVO(rdev))
|
||||
atombios_crtc_set_timing(crtc, adjusted_mode);
|
||||
else {
|
||||
atombios_crtc_set_timing(crtc, adjusted_mode);
|
||||
if (radeon_crtc->crtc_id == 0)
|
||||
|
@ -312,6 +312,20 @@ int radeon_connector_set_property(struct drm_connector *connector, struct drm_pr
|
||||
}
|
||||
}
|
||||
|
||||
if (property == rdev->mode_info.underscan_property) {
|
||||
/* need to find digital encoder on connector */
|
||||
encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
|
||||
if (!encoder)
|
||||
return 0;
|
||||
|
||||
radeon_encoder = to_radeon_encoder(encoder);
|
||||
|
||||
if (radeon_encoder->underscan_type != val) {
|
||||
radeon_encoder->underscan_type = val;
|
||||
radeon_property_change_mode(&radeon_encoder->base);
|
||||
}
|
||||
}
|
||||
|
||||
if (property == rdev->mode_info.tv_std_property) {
|
||||
encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TVDAC);
|
||||
if (!encoder) {
|
||||
@ -1120,6 +1134,9 @@ radeon_add_atom_connector(struct drm_device *dev,
|
||||
drm_connector_attach_property(&radeon_connector->base,
|
||||
rdev->mode_info.coherent_mode_property,
|
||||
1);
|
||||
drm_connector_attach_property(&radeon_connector->base,
|
||||
rdev->mode_info.underscan_property,
|
||||
UNDERSCAN_AUTO);
|
||||
if (connector_type == DRM_MODE_CONNECTOR_DVII) {
|
||||
radeon_connector->dac_load_detect = true;
|
||||
drm_connector_attach_property(&radeon_connector->base,
|
||||
@ -1145,6 +1162,9 @@ radeon_add_atom_connector(struct drm_device *dev,
|
||||
drm_connector_attach_property(&radeon_connector->base,
|
||||
rdev->mode_info.coherent_mode_property,
|
||||
1);
|
||||
drm_connector_attach_property(&radeon_connector->base,
|
||||
rdev->mode_info.underscan_property,
|
||||
UNDERSCAN_AUTO);
|
||||
subpixel_order = SubPixelHorizontalRGB;
|
||||
break;
|
||||
case DRM_MODE_CONNECTOR_DisplayPort:
|
||||
@ -1176,6 +1196,9 @@ radeon_add_atom_connector(struct drm_device *dev,
|
||||
drm_connector_attach_property(&radeon_connector->base,
|
||||
rdev->mode_info.coherent_mode_property,
|
||||
1);
|
||||
drm_connector_attach_property(&radeon_connector->base,
|
||||
rdev->mode_info.underscan_property,
|
||||
UNDERSCAN_AUTO);
|
||||
break;
|
||||
case DRM_MODE_CONNECTOR_SVIDEO:
|
||||
case DRM_MODE_CONNECTOR_Composite:
|
||||
|
@ -921,6 +921,12 @@ static struct drm_prop_enum_list radeon_tv_std_enum_list[] =
|
||||
{ TV_STD_SECAM, "secam" },
|
||||
};
|
||||
|
||||
static struct drm_prop_enum_list radeon_underscan_enum_list[] =
|
||||
{ { UNDERSCAN_OFF, "off" },
|
||||
{ UNDERSCAN_ON, "on" },
|
||||
{ UNDERSCAN_AUTO, "auto" },
|
||||
};
|
||||
|
||||
static int radeon_modeset_create_props(struct radeon_device *rdev)
|
||||
{
|
||||
int i, sz;
|
||||
@ -974,6 +980,18 @@ static int radeon_modeset_create_props(struct radeon_device *rdev)
|
||||
radeon_tv_std_enum_list[i].name);
|
||||
}
|
||||
|
||||
sz = ARRAY_SIZE(radeon_underscan_enum_list);
|
||||
rdev->mode_info.underscan_property =
|
||||
drm_property_create(rdev->ddev,
|
||||
DRM_MODE_PROP_ENUM,
|
||||
"underscan", sz);
|
||||
for (i = 0; i < sz; i++) {
|
||||
drm_property_add_enum(rdev->mode_info.underscan_property,
|
||||
i,
|
||||
radeon_underscan_enum_list[i].type,
|
||||
radeon_underscan_enum_list[i].name);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1069,17 +1087,26 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct radeon_device *rdev = dev->dev_private;
|
||||
struct drm_encoder *encoder;
|
||||
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
|
||||
struct radeon_encoder *radeon_encoder;
|
||||
struct drm_connector *connector;
|
||||
struct radeon_connector *radeon_connector;
|
||||
bool first = true;
|
||||
u32 src_v = 1, dst_v = 1;
|
||||
u32 src_h = 1, dst_h = 1;
|
||||
|
||||
radeon_crtc->h_border = 0;
|
||||
radeon_crtc->v_border = 0;
|
||||
|
||||
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
|
||||
if (encoder->crtc != crtc)
|
||||
continue;
|
||||
radeon_encoder = to_radeon_encoder(encoder);
|
||||
connector = radeon_get_connector_for_encoder(encoder);
|
||||
radeon_connector = to_radeon_connector(connector);
|
||||
|
||||
if (first) {
|
||||
/* set scaling */
|
||||
if (radeon_encoder->rmx_type == RMX_OFF)
|
||||
@ -1097,6 +1124,20 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
|
||||
memcpy(&radeon_crtc->native_mode,
|
||||
&radeon_encoder->native_mode,
|
||||
sizeof(struct drm_display_mode));
|
||||
|
||||
/* fix up for overscan on hdmi */
|
||||
if (ASIC_IS_AVIVO(rdev) &&
|
||||
((radeon_encoder->underscan_type == UNDERSCAN_ON) ||
|
||||
((radeon_encoder->underscan_type == UNDERSCAN_AUTO) &&
|
||||
drm_detect_hdmi_monitor(radeon_connector->edid)))) {
|
||||
radeon_crtc->h_border = (mode->hdisplay >> 5) + 16;
|
||||
radeon_crtc->v_border = (mode->vdisplay >> 5) + 16;
|
||||
radeon_crtc->rmx_type = RMX_FULL;
|
||||
src_v = crtc->mode.vdisplay;
|
||||
dst_v = crtc->mode.vdisplay - (radeon_crtc->v_border * 2);
|
||||
src_h = crtc->mode.hdisplay;
|
||||
dst_h = crtc->mode.hdisplay - (radeon_crtc->h_border * 2);
|
||||
}
|
||||
first = false;
|
||||
} else {
|
||||
if (radeon_crtc->rmx_type != radeon_encoder->rmx_type) {
|
||||
|
@ -212,7 +212,7 @@ void radeon_encoder_set_active_device(struct drm_encoder *encoder)
|
||||
}
|
||||
}
|
||||
|
||||
static struct drm_connector *
|
||||
struct drm_connector *
|
||||
radeon_get_connector_for_encoder(struct drm_encoder *encoder)
|
||||
{
|
||||
struct drm_device *dev = encoder->dev;
|
||||
@ -1694,6 +1694,7 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t su
|
||||
radeon_encoder->encoder_id = encoder_id;
|
||||
radeon_encoder->devices = supported_device;
|
||||
radeon_encoder->rmx_type = RMX_OFF;
|
||||
radeon_encoder->underscan_type = UNDERSCAN_OFF;
|
||||
|
||||
switch (radeon_encoder->encoder_id) {
|
||||
case ENCODER_OBJECT_ID_INTERNAL_LVDS:
|
||||
@ -1707,6 +1708,7 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t su
|
||||
} else {
|
||||
drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS);
|
||||
radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder);
|
||||
radeon_encoder->underscan_type = UNDERSCAN_AUTO;
|
||||
}
|
||||
drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs);
|
||||
break;
|
||||
@ -1736,6 +1738,7 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t su
|
||||
} else {
|
||||
drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS);
|
||||
radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder);
|
||||
radeon_encoder->underscan_type = UNDERSCAN_AUTO;
|
||||
}
|
||||
drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs);
|
||||
break;
|
||||
|
@ -66,6 +66,12 @@ enum radeon_tv_std {
|
||||
TV_STD_PAL_N,
|
||||
};
|
||||
|
||||
enum radeon_underscan_type {
|
||||
UNDERSCAN_OFF,
|
||||
UNDERSCAN_ON,
|
||||
UNDERSCAN_AUTO,
|
||||
};
|
||||
|
||||
enum radeon_hpd_id {
|
||||
RADEON_HPD_1 = 0,
|
||||
RADEON_HPD_2,
|
||||
@ -226,10 +232,12 @@ struct radeon_mode_info {
|
||||
struct drm_property *coherent_mode_property;
|
||||
/* DAC enable load detect */
|
||||
struct drm_property *load_detect_property;
|
||||
/* TV standard load detect */
|
||||
/* TV standard */
|
||||
struct drm_property *tv_std_property;
|
||||
/* legacy TMDS PLL detect */
|
||||
struct drm_property *tmds_pll_property;
|
||||
/* underscan */
|
||||
struct drm_property *underscan_property;
|
||||
/* hardcoded DFP edid from BIOS */
|
||||
struct edid *bios_hardcoded_edid;
|
||||
|
||||
@ -266,6 +274,8 @@ struct radeon_crtc {
|
||||
uint32_t legacy_display_base_addr;
|
||||
uint32_t legacy_cursor_offset;
|
||||
enum radeon_rmx_type rmx_type;
|
||||
u8 h_border;
|
||||
u8 v_border;
|
||||
fixed20_12 vsc;
|
||||
fixed20_12 hsc;
|
||||
struct drm_display_mode native_mode;
|
||||
@ -354,6 +364,7 @@ struct radeon_encoder {
|
||||
uint32_t flags;
|
||||
uint32_t pixel_clock;
|
||||
enum radeon_rmx_type rmx_type;
|
||||
enum radeon_underscan_type underscan_type;
|
||||
struct drm_display_mode native_mode;
|
||||
void *enc_priv;
|
||||
int audio_polling_active;
|
||||
@ -392,7 +403,7 @@ struct radeon_connector {
|
||||
uint32_t connector_id;
|
||||
uint32_t devices;
|
||||
struct radeon_i2c_chan *ddc_bus;
|
||||
/* some systems have a an hdmi and vga port with a shared ddc line */
|
||||
/* some systems have an hdmi and vga port with a shared ddc line */
|
||||
bool shared_ddc;
|
||||
bool use_digital;
|
||||
/* we need to mind the EDID between detect
|
||||
@ -414,6 +425,9 @@ radeon_combios_get_tv_info(struct radeon_device *rdev);
|
||||
extern enum radeon_tv_std
|
||||
radeon_atombios_get_tv_info(struct radeon_device *rdev);
|
||||
|
||||
extern struct drm_connector *
|
||||
radeon_get_connector_for_encoder(struct drm_encoder *encoder);
|
||||
|
||||
extern void radeon_connector_hotplug(struct drm_connector *connector);
|
||||
extern bool radeon_dp_needs_link_train(struct radeon_connector *radeon_connector);
|
||||
extern int radeon_dp_mode_valid_helper(struct radeon_connector *radeon_connector,
|
||||
|
Loading…
Reference in New Issue
Block a user