Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 1178 → Rev 1179

/drivers/video/drm/radeon/radeon_connectors.c
28,6 → 28,7
#include "drm_crtc_helper.h"
#include "radeon_drm.h"
#include "radeon.h"
#include "atom.h"
 
extern void
radeon_combios_connected_scratch_regs(struct drm_connector *connector,
38,6 → 39,15
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)
{
77,6 → 87,27
}
}
 
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];
83,8 → 114,6
struct drm_mode_object *obj;
struct drm_encoder *encoder;
 
ENTRY();
 
/* pick the encoder ids */
if (enc_id) {
obj = drm_mode_object_find(connector->dev, enc_id, DRM_MODE_OBJECT_ENCODER);
96,6 → 125,53
return NULL;
}
 
/*
* radeon_connector_analog_encoder_conflict_solve
* - search for other connectors sharing this encoder
* if priority is true, then set them disconnected if this is connected
* if priority is false, set us disconnected if they are connected
*/
static enum drm_connector_status
radeon_connector_analog_encoder_conflict_solve(struct drm_connector *connector,
struct drm_encoder *encoder,
enum drm_connector_status current_status,
bool priority)
{
struct drm_device *dev = connector->dev;
struct drm_connector *conflict;
int i;
 
list_for_each_entry(conflict, &dev->mode_config.connector_list, head) {
if (conflict == connector)
continue;
 
for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
if (conflict->encoder_ids[i] == 0)
break;
 
/* if the IDs match */
if (conflict->encoder_ids[i] == encoder->base.id) {
if (conflict->status != connector_status_connected)
continue;
 
if (priority == true) {
DRM_INFO("1: conflicting encoders switching off %s\n", drm_get_connector_name(conflict));
DRM_INFO("in favor of %s\n", drm_get_connector_name(connector));
conflict->status = connector_status_disconnected;
radeon_connector_update_scratch_regs(conflict, connector_status_disconnected);
} else {
DRM_INFO("2: conflicting encoders switching off %s\n", drm_get_connector_name(connector));
DRM_INFO("in favor of %s\n", drm_get_connector_name(conflict));
current_status = connector_status_disconnected;
}
break;
}
}
}
return current_status;
 
}
 
static struct drm_display_mode *radeon_fp_native_mode(struct drm_encoder *encoder)
{
struct drm_device *dev = encoder->dev;
128,13 → 204,172
return mode;
}
 
static void radeon_add_common_modes(struct drm_encoder *encoder, struct drm_connector *connector)
{
struct drm_device *dev = encoder->dev;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct drm_display_mode *mode = NULL;
struct radeon_native_mode *native_mode = &radeon_encoder->native_mode;
int i;
struct mode_size {
int w;
int h;
} common_modes[17] = {
{ 640, 480},
{ 720, 480},
{ 800, 600},
{ 848, 480},
{1024, 768},
{1152, 768},
{1280, 720},
{1280, 800},
{1280, 854},
{1280, 960},
{1280, 1024},
{1440, 900},
{1400, 1050},
{1680, 1050},
{1600, 1200},
{1920, 1080},
{1920, 1200}
};
 
for (i = 0; i < 17; i++) {
if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
if (common_modes[i].w > native_mode->panel_xres ||
common_modes[i].h > native_mode->panel_yres ||
(common_modes[i].w == native_mode->panel_xres &&
common_modes[i].h == native_mode->panel_yres))
continue;
}
if (common_modes[i].w < 320 || common_modes[i].h < 200)
continue;
 
mode = drm_cvt_mode(dev, common_modes[i].w, common_modes[i].h, 60, false, false);
drm_mode_probed_add(connector, mode);
}
}
 
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;
}
 
static void radeon_fixup_lvds_native_mode(struct drm_encoder *encoder,
struct drm_connector *connector)
{
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct radeon_native_mode *native_mode = &radeon_encoder->native_mode;
 
/* Try to get native mode details from EDID if necessary */
if (!native_mode->dotclock) {
struct drm_display_mode *t, *mode;
 
list_for_each_entry_safe(mode, t, &connector->probed_modes, head) {
if (mode->hdisplay == native_mode->panel_xres &&
mode->vdisplay == native_mode->panel_yres) {
native_mode->hblank = mode->htotal - mode->hdisplay;
native_mode->hoverplus = mode->hsync_start - mode->hdisplay;
native_mode->hsync_width = mode->hsync_end - mode->hsync_start;
native_mode->vblank = mode->vtotal - mode->vdisplay;
native_mode->voverplus = mode->vsync_start - mode->vdisplay;
native_mode->vsync_width = mode->vsync_end - mode->vsync_start;
native_mode->dotclock = mode->clock;
DRM_INFO("Determined LVDS native mode details from EDID\n");
break;
}
}
}
if (!native_mode->dotclock) {
DRM_INFO("No LVDS native mode details, disabling RMX\n");
radeon_encoder->rmx_type = RMX_OFF;
}
}
 
static int radeon_lvds_get_modes(struct drm_connector *connector)
{
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
145,6 → 380,12
if (radeon_connector->ddc_bus) {
ret = radeon_ddc_get_modes(radeon_connector);
if (ret > 0) {
encoder = radeon_best_single_encoder(connector);
if (encoder) {
radeon_fixup_lvds_native_mode(encoder, connector);
/* add scaled modes */
radeon_add_common_modes(encoder, connector);
}
return ret;
}
}
158,7 → 399,10
if (mode) {
ret = 1;
drm_mode_probed_add(connector, mode);
/* add scaled modes */
radeon_add_common_modes(encoder, connector);
}
 
return ret;
}
 
188,6 → 432,42
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,
199,7 → 479,7
.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)
215,7 → 495,6
static int radeon_vga_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
 
return MODE_OK;
}
 
227,6 → 506,10
bool dret;
enum drm_connector_status ret = connector_status_disconnected;
 
encoder = radeon_best_single_encoder(connector);
if (!encoder)
ret = connector_status_disconnected;
 
radeon_i2c_do_lock(radeon_connector, 1);
dret = radeon_ddc_probe(radeon_connector);
radeon_i2c_do_lock(radeon_connector, 0);
233,16 → 516,14
if (dret)
ret = connector_status_connected;
else {
/* if EDID fails to a load detect */
encoder = radeon_best_single_encoder(connector);
if (!encoder)
ret = connector_status_disconnected;
else {
if (radeon_connector->dac_load_detect) {
encoder_funcs = encoder->helper_private;
ret = encoder_funcs->detect(encoder, connector);
}
}
 
if (ret == connector_status_connected)
ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, true);
radeon_connector_update_scratch_regs(connector, ret);
return ret;
}
261,6 → 542,73
.set_property = radeon_connector_set_property,
};
 
static int radeon_tv_get_modes(struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
struct radeon_device *rdev = dev->dev_private;
struct drm_display_mode *tv_mode;
struct drm_encoder *encoder;
 
encoder = radeon_best_single_encoder(connector);
if (!encoder)
return 0;
 
/* avivo chips can scale any mode */
if (rdev->family >= CHIP_RS600)
/* add scaled modes */
radeon_add_common_modes(encoder, connector);
else {
/* only 800x600 is supported right now on pre-avivo chips */
tv_mode = drm_cvt_mode(dev, 800, 600, 60, false, false);
tv_mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
drm_mode_probed_add(connector, tv_mode);
}
return 1;
}
 
static int radeon_tv_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
return MODE_OK;
}
 
static enum drm_connector_status radeon_tv_detect(struct drm_connector *connector)
{
struct drm_encoder *encoder;
struct drm_encoder_helper_funcs *encoder_funcs;
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)
ret = connector_status_disconnected;
else {
encoder_funcs = encoder->helper_private;
ret = encoder_funcs->detect(encoder, connector);
}
if (ret == connector_status_connected)
ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, false);
radeon_connector_update_scratch_regs(connector, ret);
return ret;
}
 
struct drm_connector_helper_funcs radeon_tv_connector_helper_funcs = {
.get_modes = radeon_tv_get_modes,
.mode_valid = radeon_tv_mode_valid,
.best_encoder = radeon_best_single_encoder,
};
 
struct drm_connector_funcs radeon_tv_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.detect = radeon_tv_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = radeon_connector_destroy,
.set_property = radeon_connector_set_property,
};
 
static int radeon_dvi_get_modes(struct drm_connector *connector)
{
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
267,15 → 615,24
int ret;
 
ret = radeon_ddc_get_modes(radeon_connector);
/* reset scratch regs here since radeon_dvi_detect doesn't check digital bit */
radeon_connector_update_scratch_regs(connector, connector_status_connected);
return ret;
}
 
/*
* DVI is complicated
* Do a DDC probe, if DDC probe passes, get the full EDID so
* we can do analog/digital monitor detection at this point.
* If the monitor is an analog monitor or we got no DDC,
* we need to find the DAC encoder object for this connector.
* If we got no DDC, we do load detection on the DAC encoder object.
* If we got analog DDC or load detection passes on the DAC encoder
* we have to check if this analog encoder is shared with anyone else (TV)
* if its shared we have to set the other connector to disconnected.
*/
static enum drm_connector_status radeon_dvi_detect(struct drm_connector *connector)
{
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
struct drm_encoder *encoder;
struct drm_encoder *encoder = NULL;
struct drm_encoder_helper_funcs *encoder_funcs;
struct drm_mode_object *obj;
int i;
285,9 → 642,29
radeon_i2c_do_lock(radeon_connector, 1);
dret = radeon_ddc_probe(radeon_connector);
radeon_i2c_do_lock(radeon_connector, 0);
if (dret)
if (dret) {
radeon_i2c_do_lock(radeon_connector, 1);
radeon_connector->edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter);
radeon_i2c_do_lock(radeon_connector, 0);
 
if (!radeon_connector->edid) {
DRM_ERROR("DDC responded but not EDID found for %s\n",
drm_get_connector_name(connector));
} else {
radeon_connector->use_digital = !!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL);
 
/* if this isn't a digital monitor
then we need to make sure we don't have any
TV conflicts */
ret = connector_status_connected;
else {
}
}
 
if ((ret == connector_status_connected) && (radeon_connector->use_digital == true))
goto out;
 
/* find analog encoder */
if (radeon_connector->dac_load_detect) {
for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
if (connector->encoder_ids[i] == 0)
break;
302,15 → 679,23
 
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 = 0;
radeon_connector->use_digital = false;
}
}
break;
}
}
}
 
if ((ret == connector_status_connected) && (radeon_connector->use_digital == false) &&
encoder) {
ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, true);
}
 
out:
/* updated in get modes as well since we need to know if it's analog or digital */
radeon_connector_update_scratch_regs(connector, ret);
return ret;
324,9 → 709,6
struct drm_mode_object *obj;
struct drm_encoder *encoder;
int i;
 
ENTRY();
 
for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
if (connector->encoder_ids[i] == 0)
break;
337,7 → 719,7
 
encoder = obj_to_encoder(obj);
 
if (radeon_connector->use_digital) {
if (radeon_connector->use_digital == true) {
if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS)
return encoder;
} else {
384,6 → 766,7
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;
390,10 → 773,7
uint32_t subpixel_order = SubPixelNone;
 
/* fixme - tv/cv/din */
if ((connector_type == DRM_MODE_CONNECTOR_Unknown) ||
(connector_type == DRM_MODE_CONNECTOR_SVIDEO) ||
(connector_type == DRM_MODE_CONNECTOR_Composite) ||
(connector_type == DRM_MODE_CONNECTOR_9PinDIN))
if (connector_type == DRM_MODE_CONNECTOR_Unknown)
return;
 
/* see if we already added it */
422,6 → 802,9
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);
431,6 → 814,9
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:
448,6 → 834,12
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:
464,6 → 856,9
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:
485,6 → 880,13
case DRM_MODE_CONNECTOR_SVIDEO:
case DRM_MODE_CONNECTOR_Composite:
case DRM_MODE_CONNECTOR_9PinDIN:
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:
radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
500,6 → 902,10
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;
}
522,15 → 928,13
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;
 
/* fixme - tv/cv/din */
if ((connector_type == DRM_MODE_CONNECTOR_Unknown) ||
(connector_type == DRM_MODE_CONNECTOR_SVIDEO) ||
(connector_type == DRM_MODE_CONNECTOR_Composite) ||
(connector_type == DRM_MODE_CONNECTOR_9PinDIN))
if (connector_type == DRM_MODE_CONNECTOR_Unknown)
return;
 
/* see if we already added it */
559,6 → 963,9
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);
568,6 → 975,9
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:
577,6 → 987,9
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;
583,6 → 996,13
case DRM_MODE_CONNECTOR_SVIDEO:
case DRM_MODE_CONNECTOR_Composite:
case DRM_MODE_CONNECTOR_9PinDIN:
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:
drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type);
592,6 → 1012,9
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;
}