From 445282db9e815e7f5e82761c3c971dc9ea988d85 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 9 Sep 2009 17:40:54 +1000 Subject: drm/radeon/kms: add initial connector properties This adds: coherent mode: TMDS coherent mode for atom cards. scaling mode: LVDS scaler mode load detect: DAC load detection, DVI-I, VGA, TV tmds pll: legacy TMDS pll selection tv standard: TV standard selection. for later: other TV ones? dvi subconnector selection using std prop [contains fixes pointed out on dri-devel for atom bios mixups by Michel] Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_connectors.c | 237 ++++++++++++++++++++++++++--- 1 file changed, 216 insertions(+), 21 deletions(-) (limited to 'drivers/gpu/drm/radeon/radeon_connectors.c') diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 5ee81b6a879..af1d551f1a8 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -39,6 +39,15 @@ radeon_atombios_connected_scratch_regs(struct drm_connector *connector, struct drm_encoder *encoder, bool connected); +static void radeon_property_change_mode(struct drm_encoder *encoder) +{ + struct drm_crtc *crtc = encoder->crtc; + + if (crtc && crtc->enabled) { + drm_crtc_helper_set_mode(crtc, &crtc->mode, + crtc->x, crtc->y, crtc->fb); + } +} static void radeon_connector_update_scratch_regs(struct drm_connector *connector, enum drm_connector_status status) { @@ -78,6 +87,27 @@ radeon_connector_update_scratch_regs(struct drm_connector *connector, enum drm_c } } +struct drm_encoder *radeon_find_encoder(struct drm_connector *connector, int encoder_type) +{ + struct drm_mode_object *obj; + struct drm_encoder *encoder; + int i; + + for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { + if (connector->encoder_ids[i] == 0) + break; + + obj = drm_mode_object_find(connector->dev, connector->encoder_ids[i], DRM_MODE_OBJECT_ENCODER); + if (!obj) + continue; + + encoder = obj_to_encoder(obj); + if (encoder->encoder_type == encoder_type) + return encoder; + } + return NULL; +} + struct drm_encoder *radeon_best_single_encoder(struct drm_connector *connector) { int enc_id = connector->encoder_ids[0]; @@ -95,7 +125,6 @@ struct drm_encoder *radeon_best_single_encoder(struct drm_connector *connector) return NULL; } - /* * radeon_connector_analog_encoder_conflict_solve * - search for other connectors sharing this encoder @@ -224,6 +253,89 @@ static void radeon_add_common_modes(struct drm_encoder *encoder, struct drm_conn int radeon_connector_set_property(struct drm_connector *connector, struct drm_property *property, uint64_t val) { + struct drm_device *dev = connector->dev; + struct radeon_device *rdev = dev->dev_private; + struct drm_encoder *encoder; + struct radeon_encoder *radeon_encoder; + + if (property == rdev->mode_info.coherent_mode_property) { + struct radeon_encoder_atom_dig *dig; + + /* 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->enc_priv) + return 0; + + dig = radeon_encoder->enc_priv; + dig->coherent_mode = val ? true : false; + 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) { + encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_DAC); + } + + if (!encoder) + return 0; + + radeon_encoder = to_radeon_encoder(encoder); + if (!radeon_encoder->enc_priv) + return 0; + if (rdev->is_atom_bios) { + struct radeon_encoder_atom_dac *dac_int; + dac_int = radeon_encoder->enc_priv; + dac_int->tv_std = val; + } else { + struct radeon_encoder_tv_dac *dac_int; + dac_int = radeon_encoder->enc_priv; + dac_int->tv_std = val; + } + radeon_property_change_mode(&radeon_encoder->base); + } + + if (property == rdev->mode_info.load_detect_property) { + struct radeon_connector *radeon_connector = + to_radeon_connector(connector); + + if (val == 0) + radeon_connector->dac_load_detect = false; + else + radeon_connector->dac_load_detect = true; + } + + if (property == rdev->mode_info.tmds_pll_property) { + struct radeon_encoder_int_tmds *tmds = NULL; + bool ret = false; + /* 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); + + tmds = radeon_encoder->enc_priv; + if (!tmds) + return 0; + + if (val == 0) { + if (rdev->is_atom_bios) + ret = radeon_atombios_get_tmds_info(radeon_encoder, tmds); + else + ret = radeon_legacy_get_tmds_info_from_combios(radeon_encoder, tmds); + } + if (val == 1 || ret == false) { + radeon_legacy_get_tmds_info_from_table(radeon_encoder, tmds); + } + radeon_property_change_mode(&radeon_encoder->base); + } + return 0; } @@ -320,6 +432,42 @@ static void radeon_connector_destroy(struct drm_connector *connector) kfree(connector); } +static int radeon_lvds_set_property(struct drm_connector *connector, + struct drm_property *property, + uint64_t value) +{ + struct drm_device *dev = connector->dev; + struct radeon_encoder *radeon_encoder; + enum radeon_rmx_type rmx_type; + + DRM_DEBUG("\n"); + if (property != dev->mode_config.scaling_mode_property) + return 0; + + if (connector->encoder) + radeon_encoder = to_radeon_encoder(connector->encoder); + else { + struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; + radeon_encoder = to_radeon_encoder(connector_funcs->best_encoder(connector)); + } + + switch (value) { + case DRM_MODE_SCALE_NONE: rmx_type = RMX_OFF; break; + case DRM_MODE_SCALE_CENTER: rmx_type = RMX_CENTER; break; + case DRM_MODE_SCALE_ASPECT: rmx_type = RMX_ASPECT; break; + default: + case DRM_MODE_SCALE_FULLSCREEN: rmx_type = RMX_FULL; break; + } + if (radeon_encoder->rmx_type == rmx_type) + return 0; + + radeon_encoder->rmx_type = rmx_type; + + radeon_property_change_mode(&radeon_encoder->base); + return 0; +} + + struct drm_connector_helper_funcs radeon_lvds_connector_helper_funcs = { .get_modes = radeon_lvds_get_modes, .mode_valid = radeon_lvds_mode_valid, @@ -331,7 +479,7 @@ struct drm_connector_funcs radeon_lvds_connector_funcs = { .detect = radeon_lvds_detect, .fill_modes = drm_helper_probe_single_connector_modes, .destroy = radeon_connector_destroy, - .set_property = radeon_connector_set_property, + .set_property = radeon_lvds_set_property, }; static int radeon_vga_get_modes(struct drm_connector *connector) @@ -368,8 +516,10 @@ static enum drm_connector_status radeon_vga_detect(struct drm_connector *connect if (dret) ret = connector_status_connected; else { - encoder_funcs = encoder->helper_private; - ret = encoder_funcs->detect(encoder, connector); + if (radeon_connector->dac_load_detect) { + encoder_funcs = encoder->helper_private; + ret = encoder_funcs->detect(encoder, connector); + } } if (ret == connector_status_connected) @@ -426,7 +576,11 @@ static enum drm_connector_status radeon_tv_detect(struct drm_connector *connecto { struct drm_encoder *encoder; struct drm_encoder_helper_funcs *encoder_funcs; - int ret; + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + enum drm_connector_status ret = connector_status_disconnected; + + if (!radeon_connector->dac_load_detect) + return ret; encoder = radeon_best_single_encoder(connector); if (!encoder) @@ -510,27 +664,29 @@ static enum drm_connector_status radeon_dvi_detect(struct drm_connector *connect goto out; /* find analog encoder */ - for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { - if (connector->encoder_ids[i] == 0) - break; + if (radeon_connector->dac_load_detect) { + for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { + if (connector->encoder_ids[i] == 0) + break; - obj = drm_mode_object_find(connector->dev, - connector->encoder_ids[i], - DRM_MODE_OBJECT_ENCODER); - if (!obj) - continue; + obj = drm_mode_object_find(connector->dev, + connector->encoder_ids[i], + DRM_MODE_OBJECT_ENCODER); + if (!obj) + continue; - encoder = obj_to_encoder(obj); + encoder = obj_to_encoder(obj); - encoder_funcs = encoder->helper_private; - if (encoder_funcs->detect) { - if (ret != connector_status_connected) { - ret = encoder_funcs->detect(encoder, connector); - if (ret == connector_status_connected) { - radeon_connector->use_digital = false; + encoder_funcs = encoder->helper_private; + if (encoder_funcs->detect) { + if (ret != connector_status_connected) { + ret = encoder_funcs->detect(encoder, connector); + if (ret == connector_status_connected) { + radeon_connector->use_digital = false; + } } + break; } - break; } } @@ -610,6 +766,7 @@ radeon_add_atom_connector(struct drm_device *dev, bool linkb, uint32_t igp_lane_info) { + struct radeon_device *rdev = dev->dev_private; struct drm_connector *connector; struct radeon_connector *radeon_connector; struct radeon_connector_atom_dig *radeon_dig_connector; @@ -645,6 +802,9 @@ radeon_add_atom_connector(struct drm_device *dev, if (!radeon_connector->ddc_bus) goto failed; } + drm_connector_attach_property(&radeon_connector->base, + rdev->mode_info.load_detect_property, + 1); break; case DRM_MODE_CONNECTOR_DVIA: drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); @@ -654,6 +814,9 @@ radeon_add_atom_connector(struct drm_device *dev, if (!radeon_connector->ddc_bus) goto failed; } + drm_connector_attach_property(&radeon_connector->base, + rdev->mode_info.load_detect_property, + 1); break; case DRM_MODE_CONNECTOR_DVII: case DRM_MODE_CONNECTOR_DVID: @@ -671,6 +834,12 @@ radeon_add_atom_connector(struct drm_device *dev, goto failed; } subpixel_order = SubPixelHorizontalRGB; + drm_connector_attach_property(&radeon_connector->base, + rdev->mode_info.coherent_mode_property, + 1); + drm_connector_attach_property(&radeon_connector->base, + rdev->mode_info.load_detect_property, + 1); break; case DRM_MODE_CONNECTOR_HDMIA: case DRM_MODE_CONNECTOR_HDMIB: @@ -687,6 +856,9 @@ radeon_add_atom_connector(struct drm_device *dev, if (!radeon_connector->ddc_bus) goto failed; } + drm_connector_attach_property(&radeon_connector->base, + rdev->mode_info.coherent_mode_property, + 1); subpixel_order = SubPixelHorizontalRGB; break; case DRM_MODE_CONNECTOR_DisplayPort: @@ -712,6 +884,9 @@ radeon_add_atom_connector(struct drm_device *dev, drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type); drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs); } + drm_connector_attach_property(&radeon_connector->base, + rdev->mode_info.load_detect_property, + 1); break; case DRM_MODE_CONNECTOR_LVDS: radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL); @@ -727,6 +902,10 @@ radeon_add_atom_connector(struct drm_device *dev, if (!radeon_connector->ddc_bus) goto failed; } + drm_mode_create_scaling_mode_property(dev); + drm_connector_attach_property(&radeon_connector->base, + dev->mode_config.scaling_mode_property, + DRM_MODE_SCALE_FULLSCREEN); subpixel_order = SubPixelHorizontalRGB; break; } @@ -749,6 +928,7 @@ radeon_add_legacy_connector(struct drm_device *dev, int connector_type, struct radeon_i2c_bus_rec *i2c_bus) { + struct radeon_device *rdev = dev->dev_private; struct drm_connector *connector; struct radeon_connector *radeon_connector; uint32_t subpixel_order = SubPixelNone; @@ -783,6 +963,9 @@ radeon_add_legacy_connector(struct drm_device *dev, if (!radeon_connector->ddc_bus) goto failed; } + drm_connector_attach_property(&radeon_connector->base, + rdev->mode_info.load_detect_property, + 1); break; case DRM_MODE_CONNECTOR_DVIA: drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); @@ -792,6 +975,9 @@ radeon_add_legacy_connector(struct drm_device *dev, if (!radeon_connector->ddc_bus) goto failed; } + drm_connector_attach_property(&radeon_connector->base, + rdev->mode_info.load_detect_property, + 1); break; case DRM_MODE_CONNECTOR_DVII: case DRM_MODE_CONNECTOR_DVID: @@ -801,6 +987,9 @@ radeon_add_legacy_connector(struct drm_device *dev, radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI"); if (!radeon_connector->ddc_bus) goto failed; + drm_connector_attach_property(&radeon_connector->base, + rdev->mode_info.load_detect_property, + 1); } subpixel_order = SubPixelHorizontalRGB; break; @@ -810,6 +999,9 @@ radeon_add_legacy_connector(struct drm_device *dev, if (radeon_tv == 1) { drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type); drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs); + drm_connector_attach_property(&radeon_connector->base, + rdev->mode_info.load_detect_property, + 1); } break; case DRM_MODE_CONNECTOR_LVDS: @@ -820,6 +1012,9 @@ radeon_add_legacy_connector(struct drm_device *dev, if (!radeon_connector->ddc_bus) goto failed; } + drm_connector_attach_property(&radeon_connector->base, + dev->mode_config.scaling_mode_property, + DRM_MODE_SCALE_FULLSCREEN); subpixel_order = SubPixelHorizontalRGB; break; } -- cgit v1.2.2